您的模型有点混乱,这就是为什么 EF Core 约定在涉及到您的导航属性及其对应的外键时会变得混乱。
查看以下示例代码,它显示了代码和模型的完整工作修复版本:
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");
}
}
}
它生成一个如下所示的数据库:
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`);
将为示例中的查询生成以下 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)
简而言之,您正在对不应该使用的对象状态使用继承。您可以使用 anenum
代替(如示例代码所示)。