Как отношение модели 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 загрузить коллекцию, если вы не захотите загрузить ее.