【问题标题】:EF Core - Reuse the same join table entity for several relationshipsEF Core - 为多个关系重用相同的连接表实体
【发布时间】:2019-07-25 12:31:19
【问题描述】:

我想为其他几个对象(课程、讲座、游戏)重用相同的多对多关系表 (FileInEntity),因为它们都可以有文件。由于我们必须通过创建连接实体来手动创建多对多关系,因此我想为对象(课程、讲座、游戏)重用连接实体。

如果我们看一下表结构,我想有以下内容:

课程:身份证,...

讲座:身份证,...

游戏:ID,...

FileInEntity:EntityId(可以是 Course.Id、Lecture.Id 或 Game.Id)、FileId

文件:ID,... (文件是基类类型,有两种派生类型:图像和音频)

当我在 .NET Core 中尝试这种方法时,我收到以下错误消息:

实体类型“FileInEntities”处于阴影状态。一个有效的模型需要 所有实体类型都有对应的 CLR 类型。

这可能吗?


这是我的设置:

ModelBase.cs

public class ModelBase
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }
}

课程.cs

[Table("Courses")]
public class Course : ModelBase
{
    private ICollection<FileInEntity> IconsInCourse { get; set; } = new List<FileInEntity>();

    [NotMapped]
    public File Image => IconsInCourse.Select(e => e.File).FirstOrDefault();
}

Lecture.cs

// Same as Course.cs

Game.cs

// Same as Course.cs

FileInEntity.cs

[Table("FilesInEntities")]
public class FileInEntity
{
    public Guid FileId { get; set; }

    public Guid EntityId { get; set; }

    public virtual ModelBase Entity { get; set; }

    public virtual File File { get; set; }
}

文件.cs

[Table("Files")]
public class File : ModelBase
{
    // This is the property for which the error occured
    private ICollection<FileInEntity> FileInEntities { get; set; } = new List<FileInEntity>();

    public IEnumerable<ModelBase> Entities => FileInEntities.Select(e => e.Entities);
}

FilesInEntitiesMap.cs(关系配置)

builder.HasOne(p => p.Entity)
    .WithMany()
    .HasForeignKey(k => k.EntityId);

builder.HasOne(p => p.File)
    .WithMany()
    .HasForeignKey(k => k.FileId);

文件映射.cs

// This is the key to which the error references to
builder.HasMany("FileInEntities")
    .WithOne("Entity")
    .HasForeignKey("EntityId");

【问题讨论】:

  • 你想要达到的目标是不可能的。 EF(核心)仅支持真正的基于 FK 的关系,而您正在寻找多态(或更一般地说,逻辑)关联。请参阅 Ivan Stoev 在here 中评论的内容。
  • 您所拥有的通常应该可以工作,但您不能为CourseLecture 等提供单独的表。EF Core 不支持 TPT,仅支持 TPH,其中所有派生类的所有属性在同一个基表中,并使用一个鉴别器列来确定要初始化的实际类型。

标签: c# asp.net-core entity-framework-core


【解决方案1】:

您将无法使用基类 ModelBase 作为映射类中的对象,因为 c# 不会知道从数据库返回的实际类型。您可以查看每个层次结构继承的表,但我仍然不确定您是否能够在映射表中使用它。 Here is a good article

如果你的 Course.cs、Lecture.cs 和 Game.cs 相同,只是类型不同,你可以将它们合并为一个类,并添加一个枚举属性来设置类型。

public enum EntityType{
    Game = 1,
    Lecture = 2,
    Course = 3
}

public class MyEntity : ModelBase{
    private ICollection<FileInEntity> Icons { get; set; } = new List<FileInEntity>();

    [NotMapped]
    public File Image => Icons.Select(e => e.File).FirstOrDefault();

    public EntityType EntityType {get;set;} //course, lecture, or  game
}

当您关心类型时,只需使用 where 子句。

【讨论】:

    【解决方案2】:

    请务必在DbContext's OnModelCreating 中使用Fluent Api 来确定此表的One to One relationship。 (并确保再次选择正确的参考属性)

    缺少部分代码。

    public class ModelBase
    {
        [Key]// add for primary key
        //set none always for primary keys (because guid has no auto increment)
        [DatabaseGenerated(DatabaseGeneratedOption.None)] 
        public Guid Id { get; set; }
    }
    
    
    [Table("Files")]
    public class File : ModelBase
    {
        //make it public
        public ICollection<FileInEntity> FileInEntities { get; set; } = new List<FileInEntity>(); 
    
        [NotMapped] //set not mapped
        public IEnumerable<ModelBase> Entities => FileInEntities.Select(e => e.Entities);
    
        //do it same changes for `Lacture.cs`, `Game.cs` and `Course.cs`...
    }
    

    【讨论】:

      猜你喜欢
      • 2017-04-08
      • 2020-10-28
      • 1970-01-01
      • 2021-04-25
      • 2021-06-10
      • 2022-11-30
      • 2019-11-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多