Skip to main content
 首页 » 编程设计

c#之是否可以在一个实体中拥有具有相同基类 (TPH) 的实体的多个集合属性

2024年02月04日24xxx_UU

在我的项目中,我使用 Entity Framework core 2.0。 下一个代码稍微简化了。有这样的模型:

public class Site 
{ 
    public int Id { get; set; }  
    public string Name { get; set; } 
    public ICollection<AudioLink> AudioLinks { get; set; } 
    public ICollection<VideoLink> VideoLinks { get; set; } 
} 
 
public abstract class Link 
{ 
    public int Id { get; set; }          
    public string Href { get; set; } 
 
    public int SiteId { get; set; } 
    public Site Site { get; set; } 
} 
 
public class AudioLink : Link 
{ 
} 
 
public class VideoLink : Link 
{ 
} 

我使用 Fluent API 来配置关系:

public class AppDbContext : DbContext 
{ 
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) 
    { 
    } 
 
    public DbSet<Site> Sites { get; set; } 
    public DbSet<AudioLink> AudioLinks { get; set; } 
    public DbSet<VideoLink> VideoLinks { get; set; } 
 
    protected override void OnModelCreating(ModelBuilder builder) 
    { 
        builder.Entity<Link>() 
            .HasDiscriminator<byte>("LinkType") 
            .HasValue<AudioLink>(1) 
            .HasValue<VideoLink>(2); 
 
        builder.Entity<Site >().HasMany(s => s.VideoLinks) 
            .WithOne(l => l.Site) 
            .HasForeignKey(l => l.SiteId); 
 
        builder.Entity<Site >().HasMany(s => s.AudioLinks) 
            .WithOne(l => l.Site) 
            .HasForeignKey(l => l.SiteId); 
    } 
} 

看起来迁移和数据库已正确创建。 但是当我创建新的 Site 对象时:

var site = new Site(){Id = 1, Name = "SiteA"} 
var audioLink = new AudioLink(){Id = 1, Href = "abc", Site = site}; 
 
context.Sites.Add(site); 
context.SaveChanges(); 
context.AudioLinks.Add(audioLink);// exception occurs 
context.SaveChanges(); 

抛出下一个异常“无法将‘ApplicationCore.Entities.AudioLink’类型的对象转换为‘ApplicationCore.Entities.VideoLink’类型。”
你能告诉我我做错了什么吗?

请您参考如下方法:

继承不会改变单个引用导航属性只能映射到单个反向集合导航属性的规则。

实际上发生的是第二个 HasMany/WithOne 覆盖了前一个(可能是一个错误,应该抛出异常),所以 Link. Site 映射到 Site.AudioLinks(不是 Site 是基本实体 Site 的属性,因此是共享的通过 AudioLink 和 VideoLink)。

所以你要么必须从基类中删除 Site 和 SiteId 属性并将它们放在派生类中(这将引入 2 FK 关系),或者更好使用基类型的单个集合导航属性:

public class Site 
{ 
    public int Id { get; set; }  
    public string Name { get; set; } 
    public ICollection<Link> Links { get; set; } 
} 

和映射:

builder.Entity<Site>().HasMany(s => s.Links) 
   .WithOne(l => l.Site) 
   .HasForeignKey(l => l.SiteId); 

您始终可以使用 OfType() 运算符从 Links 中获取 AudioLinks 或 VideoLinks 站点具体化后的 LINQ to Entities 查询或 LINQ to Objects。