简体   繁体   中英

Entity Framework Core 5.0 is not mapping well the mysql query

I am migrating a ASP.Net Core 2.1 application to ASP .NET 5.0, but I'm having truble with entity framework. The result in my app, does not match the result if I do the same query in MySQL

I have this query

puestoCajas = _dataContext.puestocajas
    .Include(x => x.ObjSite)
    .Include(x => x.ObjCajaState)
    .Where(x => x.Enable &&
                x.SiteId == user.ObjEmployee.SiteId)
    .ToList();

the query is

SELECT `p`.`Id`, `p`.`Abrio`, `p`.`CajaMovementId`, `p`.`CajaStateId`, `p`.`Description`, `p`.`Enable`, `p`.`SiteId`, `s`.`Id`, `s`.`Address`, `s`.`CityId`, `s`.`Email`, `s`.`Enable`, `s`.`Name`, `s`.`Phone`, `c`.`Id`, `c`.`Description`, `c`.`Discriminator`
FROM `puestocajas` AS `p`
INNER JOIN `sites` AS `s` ON `p`.`SiteId` = `s`.`Id`
INNER JOIN `cajastate` AS `c` ON `p`.`CajaStateId` = `c`.`Id`
WHERE `p`.`Enable` AND (`p`.`SiteId` = 7);

I've copied from Visual Studio output window and the result when I do it directly in MySQL is // Notice the CajaStateId and ObjCajaState are not matching, I can't figured why is this happening.

Id Abrio CajaMovementId CajaStateId Description Enable SiteId Id Address CityId Email Enable Name Phone Id Description Discriminator
'4' 'Employee1' '4' '1' 'Puesto 2' '1' '7' '7' 'Address 1 ' '900014' 'examplemail@gmail.com' '1' 'San Miguel' '03811234567' '1' 'Abierta' 'CajaOpened'

In my app the result is the following:

In my app the result is the following: 
puestocajas [1]= {
    Abrio = "Employee1", 
    CajaMovementId=4,
    CajaMovements,
    CajaStateId = 1,
    Description = Puesto 2,
    Enable = true,
    Id=4,
    **ObjCajaState {
        Description = "Cerrada",
        Id= 2
    }**,
    ObjSite,
    SiteId
}
public class PuestoCaja
{
    public int Id 
    public string Description 
    public Site ObjSite 
    public int SiteId 
    public bool Enable 
    public CajaState ObjCajaState 
    public List<CajaMovement> CajaMovements 
    public int? CajaMovementId 
    public int CajaStateId 
    public string Abrio 
}

public abstract class CajaState
{
    public int Id {get; set;}
    public string Description {get; set;}
}

public class CajaOpened : CajaState
{
    public CajaOpened()
    {
        this.Id = 1;
        this.Description = "Abierta";
    }
}

public class CajaClosed : CajaState
{
    public CajaClosed()
    {
        this.Id = 2;
        this.Description = "Cerrada";
    }
}

Somehow, Pomelo Entity Framework Core didn't map the navigation properties. I have to configure them in the model builder and it worked that way.

Your model is a bit messed-up, which is why the EF Core conventions are getting confused when it comes to your navigation properties and their corresponding foreign keys.

Take a look at the following sample code, that shows a fully working fixed-up version of your code and model:

using System;
using System.Diagnostics;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace IssueConsoleTemplate
{
    public class BoxSite
    {
        public int Id { get; set; }
        public string Description { get; set; }
        public bool Enabled { get; set; }

        public int SiteId { get; set; }
        public BoxState State { get; set; }
        public int? BoxMovementId { get; set; }

        public Site ObjSite { get; set; }
        public BoxState ObjBoxState { get; set; }
        public BoxMovement ObjBoxMovement { get; set; }
    }

    public class Site
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Address { get; set; }
        public string Phone { get; set; }
        public string Email { get; set; }
        public bool Enabled { get; set; }
        
        public int CityId { get; set; }
        
        public City ObjCity { get; set; }
    }

    public class BoxMovement
    {
        public int Id { get; set; }

        public int DestinationSiteId { get; set; }
        
        public Site DestinationSite { get; set; }
    }

    public class City
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public enum BoxState
    {
        Opened = 1,
        Closed = 2,
    }

    public class Context : DbContext
    {
        public DbSet<BoxSite> BoxSites { get; set; }
        public DbSet<Site> Sites { get; set; }
        public DbSet<City> Cities { get; set; }
        public DbSet<BoxMovement> BoxMovements { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (!optionsBuilder.IsConfigured)
            {
                var connectionString = "server=127.0.0.1;port=3306;user=root;password=;database=So67874766";
                var serverVersion = ServerVersion.AutoDetect(connectionString);
                optionsBuilder.UseMySql(
                        connectionString,
                        serverVersion,
                        options => options.CommandTimeout((int) TimeSpan.FromMinutes(2).TotalSeconds))
                    .UseLoggerFactory(
                        LoggerFactory.Create(
                            configure => configure
                                .AddConsole()
                                .AddFilter(level => level >= LogLevel.Information)))
                    .EnableSensitiveDataLogging()
                    .EnableDetailedErrors();
            }
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            //
            // Sample data:
            //
            
            modelBuilder.Entity<City>()
                .HasData(
                    new City {Id = 100, Name = "Paris"},
                    new City {Id = 200, Name = "Berlin"},
                    new City {Id = 300, Name = "New York"});

            modelBuilder.Entity<Site>()
                .HasData(
                    new Site {Id = 10, Name = "Paris Warehouse", Enabled = true, CityId = 100},
                    new Site {Id = 20, Name = "Berlin Warehouse", Enabled = true, CityId = 200},
                    new Site {Id = 30, Name = "New York Warehouse", Enabled = false, CityId = 300});

            modelBuilder.Entity<BoxSite>()
                .HasData(
                    new BoxSite
                    {
                        Id = 1,
                        Description = "Opened Vanilla Ice Cream Box in Paris",
                        Enabled = true,
                        SiteId = 10,
                        State = BoxState.Opened,
                    },
                    new BoxSite
                    {
                        Id = 2,
                        Description = "Closed Chocolate Ice Cream Box in Berlin",
                        Enabled = true,
                        SiteId = 20,
                        State = BoxState.Closed,
                    },
                    new BoxSite
                    {
                        Id = 3,
                        Description = "Closed Matcha Ice Cream Box New York",
                        Enabled = true,
                        SiteId = 30,
                        State = BoxState.Closed,
                    });
        }
    }

    internal static class Program
    {
        private static void Main()
        {
            using var context = new Context();

            context.Database.EnsureDeleted();
            context.Database.EnsureCreated();

            var berlinWarehouseSiteId = 20;

            var boxesInBerlin = context.BoxSites
                .Include(b => b.ObjSite)
                .Where(b => b.Enabled &&
                            b.SiteId == berlinWarehouseSiteId)
                .ToList();
            
            Trace.Assert(boxesInBerlin.Count == 1);
            Trace.Assert(boxesInBerlin[0].Description == "Closed Chocolate Ice Cream Box in Berlin");
        }
    }
}

It generates a database looking like this:

CREATE DATABASE `So67874766`;
ALTER DATABASE CHARACTER SET utf8mb4;

CREATE TABLE `Cities` (
    `Id` int NOT NULL AUTO_INCREMENT,
    `Name` longtext CHARACTER SET utf8mb4 NULL,
    CONSTRAINT `PK_Cities` PRIMARY KEY (`Id`)
) CHARACTER SET utf8mb4;

CREATE TABLE `Sites` (
    `Id` int NOT NULL AUTO_INCREMENT,
    `Name` longtext CHARACTER SET utf8mb4 NULL,
    `Address` longtext CHARACTER SET utf8mb4 NULL,
    `Phone` longtext CHARACTER SET utf8mb4 NULL,
    `Email` longtext CHARACTER SET utf8mb4 NULL,
    `Enabled` tinyint(1) NOT NULL,
    `CityId` int NOT NULL,
    CONSTRAINT `PK_Sites` PRIMARY KEY (`Id`),
    CONSTRAINT `FK_Sites_Cities_CityId` FOREIGN KEY (`CityId`) REFERENCES `Cities` (`Id`) ON DELETE CASCADE
) CHARACTER SET utf8mb4;

CREATE TABLE `BoxMovements` (
    `Id` int NOT NULL AUTO_INCREMENT,
    `DestinationSiteId` int NOT NULL,
    CONSTRAINT `PK_BoxMovements` PRIMARY KEY (`Id`),
    CONSTRAINT `FK_BoxMovements_Sites_DestinationSiteId` FOREIGN KEY (`DestinationSiteId`) REFERENCES `Sites` (`Id`) ON DELETE CASCADE
) CHARACTER SET utf8mb4;

CREATE TABLE `BoxSites` (
    `Id` int NOT NULL AUTO_INCREMENT,
    `Description` longtext CHARACTER SET utf8mb4 NULL,
    `Enabled` tinyint(1) NOT NULL,
    `SiteId` int NOT NULL,
    `State` int NOT NULL,
    `BoxMovementId` int NULL,
    `ObjBoxState` int NOT NULL,
    CONSTRAINT `PK_BoxSites` PRIMARY KEY (`Id`),
    CONSTRAINT `FK_BoxSites_BoxMovements_BoxMovementId` FOREIGN KEY (`BoxMovementId`) REFERENCES `BoxMovements` (`Id`) ON DELETE RESTRICT,
    CONSTRAINT `FK_BoxSites_Sites_SiteId` FOREIGN KEY (`SiteId`) REFERENCES `Sites` (`Id`) ON DELETE CASCADE
) CHARACTER SET utf8mb4;

INSERT INTO `Cities` (`Id`, `Name`)
VALUES (100, 'Paris');

INSERT INTO `Cities` (`Id`, `Name`)
VALUES (200, 'Berlin');

INSERT INTO `Cities` (`Id`, `Name`)
VALUES (300, 'New York');

INSERT INTO `Sites` (`Id`, `Address`, `CityId`, `Email`, `Enabled`, `Name`, `Phone`)
VALUES (10, NULL, 100, NULL, TRUE, 'Paris Warehouse', NULL);

INSERT INTO `Sites` (`Id`, `Address`, `CityId`, `Email`, `Enabled`, `Name`, `Phone`)
VALUES (20, NULL, 200, NULL, TRUE, 'Berlin Warehouse', NULL);

INSERT INTO `Sites` (`Id`, `Address`, `CityId`, `Email`, `Enabled`, `Name`, `Phone`)
VALUES (30, NULL, 300, NULL, FALSE, 'New York Warehouse', NULL);

INSERT INTO `BoxSites` (`Id`, `BoxMovementId`, `Description`, `Enabled`, `ObjBoxState`, `SiteId`, `State`)
VALUES (1, NULL, 'Opened Vanilla Ice Cream Box in Paris', TRUE, 0, 10, 1);

INSERT INTO `BoxSites` (`Id`, `BoxMovementId`, `Description`, `Enabled`, `ObjBoxState`, `SiteId`, `State`)
VALUES (2, NULL, 'Closed Chocolate Ice Cream Box in Berlin', TRUE, 0, 20, 2);

INSERT INTO `BoxSites` (`Id`, `BoxMovementId`, `Description`, `Enabled`, `ObjBoxState`, `SiteId`, `State`)
VALUES (3, NULL, 'Closed Matcha Ice Cream Box New York', TRUE, 0, 30, 2);

CREATE INDEX `IX_BoxMovements_DestinationSiteId` ON `BoxMovements` (`DestinationSiteId`);
CREATE INDEX `IX_BoxSites_BoxMovementId` ON `BoxSites` (`BoxMovementId`);
CREATE INDEX `IX_BoxSites_SiteId` ON `BoxSites` (`SiteId`);
CREATE INDEX `IX_Sites_CityId` ON `Sites` (`CityId`);

The following SQL will be generated for the query in the sample:

SELECT `b`.`Id`, `b`.`BoxMovementId`, `b`.`Description`, `b`.`Enabled`, `b`.`ObjBoxState`, `b`.`SiteId`, `b`.`State`, `s`.`Id`, `s`.`Address`, `s`.`CityId`, `s`.`Email`, `s
`.`Enabled`, `s`.`Name`, `s`.`Phone`
FROM `BoxSites` AS `b`
INNER JOIN `Sites` AS `s` ON `b`.`SiteId` = `s`.`Id`
WHERE `b`.`Enabled` AND (`b`.`SiteId` = @__berlinWarehouseSiteId_0)

In short, you are using inheritance for the object states, where you shouldn't. You could use an enum instead (shown in the sample code).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM