代码优先实体框架具有多对多的多个集合

Pet*_*nge 7 ef-code-first entity-framework-5

我在这里有另一个实体框架问题.我有一个名为Book的复杂对象,该对象有许多类型为Contributor的集合,例如Writer,Letterer,Colorist等.但贡献者不一定是特定角色的范围.因此,相同的贡献者(具有相同的ContributorId)可以是Writer和Colorist.

public Book {
        public ICollection<Contributor> Writers { get; set; }
        public ICollection<Contributor> Artists { get; set; }
        public ICollection<Contributor> Pencilers { get; set; }
        public ICollection<Contributor> Inkers { get; set; }
        public ICollection<Contributor> Colorists { get; set; }
        public ICollection<Contributor> Letterers { get; set; }
        public ICollection<Contributor> CoverArtists { get; set; }
        public ICollection<Contributor> OtherContributors { get; set; }
}

public Contributor {
     public int ContributorId { get; set; }
     public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我遇到了麻烦,查看我在这里和其他网站上找到的例子,确定我将如何表示合适的模型.我希望Db Model能像这样.我想要避免的是一个模型,其中我为每个贡献者角色都有一个单独的表,或者对于每个贡献者与任何角色的书相关联的实例,在Contributor表中有一个单独的行.

+ Books 
     --BookId
+ Contributors
      --ContributorId
+ BookContributors
      --BookId
      --ContributorId
      --Discriminator
Run Code Online (Sandbox Code Playgroud)

我就像ADO.NET那样,我并不是真的觉得这太令人愉快,但我决心至少在这个重要的框架中精通边缘.

快速注意事项: 自打开这个问题以来,我在工作中被拉走了,没有时间彻底审查答案并且对结果进行了解决.但我不想放弃赏金,因为我很欣赏每个人提供的答案.所以我选择了对我来说最感兴趣的答案.我想为此感谢大家.

Par*_*hah 3

我已经研究了一个实现您提出的模型的解决方案,尽管它的工作方式与您期望的有点不同。希望这能回答您的问题。

楷模

[Table("Book")]
public class Book
{
    [Column("BookId")]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int BookId { get; set; }

    [NotMapped]
    public ICollection<Contributor> Writers { get; set; }

    [NotMapped]
    public ICollection<Contributor> Artists { get; set; }

    [NotMapped]
    public ICollection<Contributor> Pencilers { get; set; }

    [NotMapped]
    public ICollection<Contributor> Inkers { get; set; }

    [NotMapped]
    public ICollection<Contributor> Colorists { get; set; }

    [NotMapped]
    public ICollection<Contributor> Letterers { get; set; }

    [NotMapped]
    public ICollection<Contributor> CoverArtists { get; set; }

    [NotMapped]
    public ICollection<Contributor> OtherContributors { get; set; }
}

[Table("Contributor")]
public class Contributor
{
    [Column("ContributorId")]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ContributorId { get; set; }
}

// Contributor Type is one of the following options: Writer, Artist, Penciler, etc.
[Table("ContributorType")]
public class ContributorType
{
    [Column("ContributorTypeId")]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ContributorTypeId { get; set; }

    [Column("Name")]
    public string Name { get; set; }
}

[Table("BookContributor")]
public class BookContributor
{
    [Column("BookContributorId")]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int BookContributorId { get; set; }

    [Column("BookId")]
    public int BookId { get; set; }

    [Column("ContributorId")]
    public int ContributorId { get; set; }

    [Column("RoleId")]
    public int RoleId { get; set; }

    [ForeignKey("BookId")]
    public virtual Book Book { get; set; }

    [ForeignKey("ContributorId")]
    public virtual Contributor Contributor { get; set; }

    [ForeignKey("RoleId")]
    public virtual ContributorType Role { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

数据库上下文

AppDbContext.cs:

public class AppDbContext : DbContext
{
    public AppDbContext()
    {
        Database.SetInitializer<AppDbContext>(new AppDbInitializer());
    }

    public AppDbContext(string connectionString)
        : base(connectionString)
    {
        Database.SetInitializer<AppDbContext>(new AppDbInitializer());
    }

    public DbSet<Book> Books { get; set; }

    public DbSet<Contributor> Contributors { get; set; }

    public DbSet<ContributorType> ContributorTypes { get; set; }

    public DbSet<BookContributor> BookContributors { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

AppDbInitializer.cs:

public class AppDbInitializer : DropCreateDatabaseAlways<AppDbContext>
{
    protected override void Seed(AppDbContext context)
    {
        // default contributor types
        var contributorTypes = new List<ContributorType>();
        contributorTypes.Add(new ContributorType() { Name = "Writer" });
        contributorTypes.Add(new ContributorType() { Name = "Artist" });
        contributorTypes.Add(new ContributorType() { Name = "Penciler" });
        contributorTypes.Add(new ContributorType() { Name = "Inker" });
        contributorTypes.Add(new ContributorType() { Name = "Colorist" });
        contributorTypes.Add(new ContributorType() { Name = "Letterer" });
        contributorTypes.Add(new ContributorType() { Name = "CoverArtist" });
        contributorTypes.Add(new ContributorType() { Name = "OtherContributor" });

        // adding it to the context
        foreach (var type in contributorTypes)
            context.ContributorTypes.Add(type);

        base.Seed(context);
    }
}
Run Code Online (Sandbox Code Playgroud)

将所有东西包裹在一起

程序.cs:

class Program
{
    static void Main(string[] args)
    {
        // enter name of the connection string in App.Config file
        var connectionSettings = ConfigurationManager.ConnectionStrings["..."];
        using (var dbContext = new AppDbContext(connectionSettings.ConnectionString)) 
        {
            // Creating a book
            var book = new Book();
            dbContext.Books.Add(book);
            dbContext.SaveChanges();

            // Creating contributor
            var contributor = new Contributor();
            dbContext.Contributors.Add(contributor);
            dbContext.SaveChanges();

            // Adding contributor to the book
            var bookContributor = new BookContributor()
            {
                BookId = book.BookId,
                ContributorId = contributor.ContributorId,
                RoleId = dbContext.ContributorTypes.First(t => t.Name == "Writer").ContributorTypeId
            };
            dbContext.BookContributors.Add(bookContributor);
            dbContext.SaveChanges();

            // retrieving a book
            var book = dbContext.Books.Where(b => b.BookId == 2).FirstOrDefault();
            if (book != null) 
            {
                book.Writers = 
                    from contributor in dbContext.Contributors
                    join bookContributor in dbContext.BookContributors on contributor.BookId equals bookContributor.BookId
                    join contributorType in dbContext.ContributorTypes on contributorType.ContributorTypeId equals bookContributor.ContributorTypeId
                    where 
                        bookContributor.BookId == 2 and
                        contributorType.Name == "Writer"
                    select contributor;

                // do the same for other types of contributors
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)