c# – Include()ThenInclude()在Table Per Hierarchy策略中抛出
|
我正在使用Entity Framework 7和代码优先,我有一个涉及3个级别的父子关系的模型:
>公司有公司 由于这3个实体共享很多共同点,因此它们都从一个抽象的BaSEOrganization实体继承. 当我试图列出所有工厂,包括他们的母公司,然后包括他们的母公司时,我有这两种不同的情况: >不将BaSEOrganization包含到上下文中,代码优先创建三个表(对应于Table-Per-Concrete-Type或TPC模式). Include()和ThenInclude()工作正常,我可以按预期列出工厂和遍历关系. 这个问题(没有继承和抽象基类模式)已经在EF7 Github repo中得到了解决,并且已被清除(见https://github.com/aspnet/EntityFramework/issues/1460). 所以我目前不知道我的方法是否有问题,或者这显然是EF7 RC1的问题?请注意,我更喜欢保持继承,以便我的SQL模型更具可读性. 以下是完整的复制代码: using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Data.Entity;
namespace MultiLevelTest
{
// All places share name and Id
public abstract class BaSEOrganization
{
public int Id { get; set; }
public string Name { get; set; }
}
// a corporation (eg : Airbus Group)
public class Corporation : BaSEOrganization
{
public virtual ICollection<Company> Companies { get; set; } = new List<Company>();
}
// a company (eg : Airbus,Airbus Helicopters,Arianespace)
public class Company : BaSEOrganization
{
public virtual Corporation Corporation { get; set; }
public virtual ICollection<Factory> Factories { get; set; } = new List<Factory>();
}
// a factory of a company (Airbus Toulouse,Airbus US...)
public class Factory : BaSEOrganization
{
public virtual Company Company { get; set; }
}
// setup DbContext
public class MyContext : DbContext
{
// if this line is commented,then code first creates 3 tables instead of one,and everything works fine.
public DbSet<BaSEOrganization> BaSEOrganizationCollection { get; set; }
public DbSet<Corporation> Corporations { get; set; }
public DbSet<Company> Companies { get; set; }
public DbSet<Factory> Factories { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(
@"Server=(localdb)mssqllocaldb;Database=MultiLevelTest;Trusted_Connection=True;MultipleActiveResultSets=true");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Corporation>().HasMany(c => c.Companies).WithOne(c => c.Corporation);
modelBuilder.Entity<Company>().HasMany(c => c.Factories).WithOne(c => c.Company);
modelBuilder.Entity<Factory>().HasOne(f => f.Company);
}
}
public class Program
{
public static void Main(string[] args)
{
using (var ctx = new MyContext())
{
ctx.Database.EnsureDeleted();
ctx.Database.EnsureCreated();
// Add a corporation with companies then factories (this works fine)
if (!ctx.Corporations.Any()) CreateOrganizationGraph(ctx);
// Get all the factories without including anything (this is still working fine)
var simpleFactories = ctx.Factories.ToList();
foreach(var f in simpleFactories) Console.WriteLine(f.Name);
// Get all the factories including their mother company,then their mother corporation
var fullFactories = ctx.Factories
.Include(f => f.Company)
.ThenInclude(c => c.Corporation)
.ToList();
foreach (var f in fullFactories) Console.WriteLine($"{f.Company.Corporation.Name} > {f.Company.Name} > {f.Name}");
}
}
public static void CreateOrganizationGraph(MyContext ctx)
{
var airbusCorp = new Corporation()
{
Name = "Airbus Group",Companies = new List<Company>()
{
new Company
{
Name = "Airbus",Factories = new List<Factory>()
{
new Factory {Name = "Airbus Toulouse (FR)"},new Factory {Name = "Airbus Hambourg (DE)"}
}
},new Company
{
Name = "Airbus Helicopters",Factories = new List<Factory>()
{
new Factory {Name = "Eurocopter Marignane (FR)"},new Factory {Name = "Eurocopter Deutschland (DE)"}
}
}
}
};
ctx.Corporations.Add(airbusCorp);
ctx.SaveChanges();
}
}
}
您将需要包含以下NuGet包: "EntityFramework.Commands": "7.0.0-rc1-final","EntityFramework.Core": "7.0.0-rc1-final","EntityFramework.MicrosoftSqlServer": "7.0.0-rc1-final" UPDATE 正如我自己的评论中所述,我的第一个解决方法是避免在DbContext中包含基类型,以便代码优先生成具有TPC模式的模式(只有在TPH策略中才会抛出错误). 问题是上面的例子比我的实际实现更简单,它涉及在基类型级别定义的多对多关系. 由于EF7不支持(但?)支持多对多关系,因此我们必须定义一个链接实体,该实体可以自己映射两个一对多关系. 该映射实体在基类型级别定义和使用,代码优先仍然选择TPH策略,然后仍然会抛出错误. 换句话说,我被卡住了,或者我将不得不重复一些逻辑三次,这几乎就像故意破坏我自己的腿! 解决方法
我认为你不应该尝试在你的情况下使用基类.
组织,公司,工厂代表不同的对象,从我在这里看到的,你试图重构代码而不是抽象对象: 如果您创建一个存储作者和书籍的数据库,作者和书籍都会有一个名称和一个id,但是有一个基类是否有意义? 当然,您将节省几行代码,但它会降低代码的可读性. 我认为你应该在有真正的继承时使用基类: 例如,您可以拥有一个基类Person和一个继承自Person类的Manager和Employee类,因为员工和经理都是人. 对我来说,你只需删除你的基类,它应该按预期工作: public class Corporation
{
public int Id { get; set; }
public string Name { get; set; }
public List<Company> Companies { get; set; } = new List<Company>();
}
public class Company
{
public int Id { get; set; }
public string Name { get; set; }
public Corporation Corporation { get; set; }
public List<Factory> Factories { get; set; } = new List<Factory>();
}
public class Factory
{
public int Id { get; set; }
public string Name { get; set; }
public Company Company { get; set; }
}
public class MyContext : DbContext
{
public DbSet<Corporation> Corporations { get; set; }
public DbSet<Company> Companies { get; set; }
public DbSet<Factory> Factories { get; set; }
...
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Corporation>().HasMany(c => c.Companies).WithOne(c => c.Corporation);
modelBuilder.Entity<Company>().HasMany(c => c.Factories).WithOne(c => c.Company);
modelBuilder.Entity<Factory>().HasOne(f => f.Company);
}
}
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
