简体   繁体   中英

EF Core - Reuse the same join table entity for several relationships

I want to reuse the same many-to-many relationship table (FileInEntity) for several other objects (Course, Lecture, Game), since they all can have files. Since we have to manually create the many-to-many relationships by creating a join entity, I want to reuse the join entity for the objects (Course, Lecture, Game).

If we look at the table structure, I would like to have the following:

Course : Id, ...

Lecture : Id, ...

Game : Id, ...

FileInEntity : EntityId (this can be either Course.Id, Lecture.Id or Game.Id), FileId

File : Id, ... (File is base class type with two derived types: Image and Audio)

When I try this approach in .NET Core, I receive the following error message:

Entity type 'FileInEntities' is in shadow-state. A valid model requires all entity types to have corresponding CLR type.

Is this even possible?


This is my setup:

ModelBase.cs

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

Course.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; }
}

File.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 (Relationship Configuration)

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

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

FileMap.cs

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

You won't be able to use the base class ModelBase as the object in the mapping class because c# wont know the actual type coming back from the db. You can look at table per hierarchy inheritance, but I'm still not sure you would be able to use that in a mapping table either. Here is a good article

If your Course.cs, Lecture.cs, and Game.cs are the same and the only difference is type, you could combine them into one class and add an enum property to set the type.

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
}

When you care about the type just use a where clause.

Be sure to use Fluent Api in DbContext's OnModelCreating to determine One to One relationship for this tables. (and be sure again correct reference properties are selected)

Missing parts of your codes.

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`...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM