简体   繁体   English

Entity Framework Core 5.0 没有很好地映射 mysql 查询

[英]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.我正在将 ASP.Net Core 2.1 应用程序迁移到 ASP .NET 5.0,但我在实体框架方面遇到了麻烦。 The result in my app, does not match the result if I do the same query in MySQL如果我在 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.我从 Visual Studio output window 复制了结果,当我直接在 MySQL 中进行操作时,结果是 // 注意 CajaStateId 和 ObjCajaState 不匹配,我可以知道为什么会这样。

Id ID Abrio阿布里奥 CajaMovementId CajaMovementId CajaStateId CajaStateId Description描述 Enable使能够 SiteId站点 ID Id ID Address地址 CityId城市编号 Email Email Enable使能够 Name姓名 Phone电话 Id ID Description描述 Discriminator鉴别器
'4' '4' 'Employee1' '员工1' '4' '4' '1' '1' 'Puesto 2' '普埃斯托 2' '1' '1' '7' '7' '7' '7' 'Address 1 ' '地址1 ' '900014' '900014' 'examplemail@gmail.com' 'examplemail@gmail.com' '1' '1' 'San Miguel' “圣米格尔” '03811234567' '03811234567' '1' '1' 'Abierta' '阿比尔塔' 'CajaOpened' 'CajaOpen'

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.不知何故,Pomelo Entity Framework Core 没有 map 导航属性。 I have to configure them in the model builder and it worked that way.我必须在 model 构建器中配置它们,它就是这样工作的。

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.您的 model 有点混乱,这就是为什么 EF Core 约定在您的导航属性及其相应的外键方面变得混乱的原因。

Take a look at the following sample code, that shows a fully working fixed-up version of your code and model:查看以下示例代码,它显示了您的代码和 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:示例中的查询将生成以下 SQL:

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.简而言之,您将 inheritance 用于 object 状态,而您不应该这样做。 You could use an enum instead (shown in the sample code).您可以改用enum (如示例代码所示)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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