我使用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关系的确切实施。
答案 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延迟加载集合。