Как модель N - N отношения в EF Code First автоматически генерируемые представления работают правильно? - PullRequest
10 голосов
/ 22 ноября 2011

Я использую 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 генерирует представления автоматически.

Я знаю, что могу получить доступ как к жанрам, так и к исполнителям с обеих сторон, но мне интересно, чтобы MVC автоматически генерировал представления так, как мы хотим: например, для каждого художника, показывающего связанные жанры.

Как я могу это сделать? Моя модель верна? Верно ли это для любого (n к n) отношения, которое требует ICollection с обеих сторон? Или мне нужны некоторые элементы в переопределении метода OnModelCreating в классе контекста, например что-то вроде этого:

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

Пожалуйста, помогите мне, я не знаю точную реализацию отношений NtoN.

Ответы [ 4 ]

12 голосов
/ 22 ноября 2011

Вам не нужно создавать отдельный 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, EF не будет рассматривать ее как отношение, потому что вы говорите ему, что Эй, ЭФ, у меня есть другая модель с именем ArtistsGenres! Пожалуйста, сделайте это для меня !!!

Ваши новые сущности и dbcontext будут такими:

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");
        });

}

Дайте мне знать, если у вас есть какие-либо вопросы или вам нужны разъяснения по любой части.

1 голос
/ 23 ноября 2011

Я бы предложил вам перейти к более простому подходу создания другой модели ArtistGenre и позволить EF самостоятельно выяснить отношения. Создайте таблицу, как показано ниже.

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

    public virtual Genre Genre;
    public virtual Artist Artist;
}

После этого в базу данных будет добавлена ​​еще одна таблица с указанным именем с двумя внешними ключами и одним первичным ключом.

Теперь вы можете выполнять запросы к этой таблице. Скажи

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

Теперь художник будет держать всех художников в жанре с Id = 1. Вы можете сделать то же самое и для Жанров наоборот.

Надеюсь, это поможет !!

0 голосов
/ 22 ноября 2011

Проблема в том, что вы явно не загружаете коллекцию Genres класса Artist и не позволяете 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 отложит загрузку коллекции, если вы ее не стремились.

0 голосов
/ 22 ноября 2011

Связь между Artist и жанрами - это ArtistsGenre.

Таким образом, исполнитель содержит: ID, Имя

И Genre содержит: ID, Название

И ArtistsGenre содержит: IDисполнитель, ID жанра

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...