>公司有公司
>公司属于公司并拥有工厂
>工厂属于一家公司
由于这3个实体共享很多共同点,因此它们都从一个抽象的BaSEOrganization实体继承.
当我试图列出所有工厂,包括他们的母公司,然后包括他们的母公司时,我有这两种不同的情况:
>不将BaSEOrganization包含到上下文中,代码优先创建三个表(对应于Table-Per-Concrete-Type或TPC模式). Include()和ThenInclude()工作正常,我可以按预期列出工厂和遍历关系.
>将BaSEOrganization包含到上下文中,代码优先创建一个带有鉴别器字段的表(对应于Table-Per-Hierarchy或TPH模式). Include()和ThenInclude()抛出一个包含多个匹配元素异常的Sequence.
这个问题(没有继承和抽象基类模式)已经在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); } }
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。