Как отношение модели n - n в коде EF Сначала для автоматически созданных представлений работает правильно?

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

Например, мне нужно изменить жанры исполнителя в режиме редактирования, в "Создать представление" я могу установить "Жанры для исполнителя" или "Индексный вид". Я хочу показывать жанры для каждого исполнителя. Но нет никакого поколения для жанров в отношении Artist, когда MVC автоматически генерирует представления.

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

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

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

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

Ответ 1

Вам не нужно создавать отдельный 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 не будет рассматривать ее как отношения, потому что вы говорите ему, что Hey 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");
        });

}

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

Ответ 2

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

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

Ответ 3

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

Итак, artist containst: Я БЫ, Имя

И Жанр содержит: Я БЫ, Название

И ArtistsGenre содержит: ID художник, Идентификатор жанра

Ответ 4

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