EF代码中的模型n - n关系如何自动生成视图正常工作?

时间:2011-11-22 12:51:43

标签: c# .net entity-framework ef-code-first

我使用EF Code First并且在n-n关系中存在问题,假设我们有一个歌手在某些类型中唱歌,所以我们需要这个模型:Artist,Genre和ArtistsGenres,我将模型定义如下:

这是我的艺术家模特:

public class Artist
{
    public long Id { get; set; }
    public string Name { get; set; }
    public ICollection<Genre> Genres { get; set; }
}

和我的类型模型:

public class Genre
{
    public long Id { get; set; }
    public string Title { get; set; }
    public ICollection<Artist> Artists { get; set; }
}

我的上下文类:

public class MusicDB : DbContex
{
    public DbSet<Artist> Artists { get; set; }
    public DbSet<Genre> Genres { get; set; }
    public DbSet<ArtistsGenres> ArtistsGenres { get; set; }

protected override void OnModelCreating(DbModelBuilder modelBuilder) {
modelBuilder.Entity<Artist>()
            .HasMany(a => a.Genres)
            .WithMany(g => g.Artists)
            .Map(model => {
                model.ToTable("ArtistsGenres");
                model.MapLeftKey("Artist_Id");
                model.MapRightKey("Genre_Id");
            });

        base.OnModelCreating(modelBuilder);
        }
}

但是当MVC自动生成视图时,艺术家和流派之间没有任何关系。

例如,我需要在编辑视图中更改艺术家的类型,在创建视图中我可以为艺术家设置流派,或者在索引视图中我想要为每个艺术家显示流派。但是当MVC自动生成视图时,与Artist相关的Genres没有任何代。

我知道我可以从两边访问流派和艺术家,但我很有兴趣MVC自动生成我们想要的视图:例如:每个艺术家节目相关的流派。

我该怎么做?我的模特是否正确?这对于任何需要ICollection的(n到n)关系都是如此吗?或者在上下文类中覆盖OnModelCreating方法时是否需要一些元素,例如:

modelBuilder.Entity<Artist>()
    .HasMany(a => a.Genres)
    .WithMany(g => g.Artists);

请帮助我,我不知道NtoN关系的确切实施。

4 个答案:

答案 0 :(得分:12)

您不必为多对多关系中的模型之间的关联创建单独的Model。实际上ArtistsGenres不是必需的。所以,删除它,你只需要将modelBuilder更改为这个:

modelBuilder.Entity<Artist>()
    .HasMany(c => c.Genres)
    .WithMany(x => x.Artists)
    .Map(a => {
        a.ToTable("ArtistsGenres");
        a.MapLeftKey("ArtistId");
        a.MapRightKey("GenreId");
    });

它将使用ArtistsGenres表来映射Artists表和Genres表之间的多对多关系 自动ArtistsGenres表。

注意:当您定义ArtistsGenres模型时,EF不会将其视为关系, 因为你告诉他嘿EF,我有另一个名为public class Artist { public long Id { get; set; } public string Name { get; set; } public ICollection<Genre> Genres { get; set; } } public class Genre { public long Id { get; set; } public string Title { get; set; } public ICollection<Artist> Artists { get; set; } } public class MusicDB : DbContex { public DbSet<Artist> Artists { get; set; } public DbSet<Genre> Genres { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity<Artist>() .HasMany(c => c.Genres) .WithMany(x => x.Artists) .Map(a => { a.ToTable("ArtistsGenres"); a.MapLeftKey("ArtistId"); a.MapRightKey("GenreId"); }); } 的模特!请为我管理!!!

您的新实体和dbcontext将是:

{{1}}

如果您对任何部分有任何疑问或需要澄清,请与我们联系。

答案 1 :(得分:1)

我建议你采用更简单的方法来创建另一个模型ArtistGenre,并让EF自己找出关系。创建如下表格。

public class ArtistGenre
{
    public int Id;
    public int GenreId;
    public int ArtistId;

    public virtual Genre Genre;
    public virtual Artist Artist;
}

之后,您将通过上述名称将另一个表添加到数据库中,其中包含两个foriegn键属性和一个主键。

现在,您可以在此表上运行查询。说

var artist = myContext.ArtistGenre.where( g = g.GenreId == 1).ToList();

现在,艺术家将把所有艺术家保持在流派下,Id = 1。你也可以用类似的方式为Genres做反之亦然。

希望它有所帮助!!

答案 2 :(得分:0)

艺术家和流派之间的联系是ArtistsGenre。

所以艺术家包含: ID, 名称

而且类型包含: ID, 标题

ArtistsGenre包含: ID艺术家, ID类型

答案 3 :(得分:0)

问题是您未明确加载艺术家类的Genres集合,并且您不允许EF通过不将其声明为virtual来拦截该属性访问。

public class Artist
{
    public long Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Genre> Genres { get; set; }
}

然后,当您需要访问艺术家和相关类型时,您需要急切加载它们

var artist = db.Artists.Include(a => a.Genres)
      .Where(a => a.Name == "Foo").SingleOrDefault()

如果你没有急切地加载它,那么使Genres属性为虚拟将允许EF延迟加载集合。