Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How Model n--n relationship in EF Code First to automatically generated views work correctly?

I use EF Code First and have a problem in n-n relationship, assume we have a singer that sing in some genres, so we need this models: Artist, Genre, and ArtistsGenres, I define Models as following:

This is My Artist Model:

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

And My Genre Model:

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

And my context class:

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

But there is not any relationship between Artists and Genres when MVC generate views automatically.

For example, I need to change Genres of an Artist in edit view, in Create view I can set Genres for an Artist, or in Index View I want show genres for each Artist. But there isn't any generation for Genres in relation to Artist when MVC generate views automatically.

I know I can access both Genres and Artists from both side but I am interesting in MVC automatically generate views as we want: for ex: for each artist show related Genres.

How can I do this? Is my model correct? Is this true for any (n to n) relation that needs ICollection on both side? Or do I need some elements in overriding of OnModelCreating method in context class, for example something like this:

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

Please help me, I don't know the exact implementation of NtoN relationship.

like image 459
Saeid Avatar asked Nov 22 '11 12:11

Saeid


1 Answers

You haven't to create a separate Model for association between to models in a many-to-many relationship. Really the ArtistsGenres is not necessary. So, remove it, and you just have to change your modelBuilder to this one:

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

It will use the ArtistsGenres table to map a many-to-many relationship between Artists table and Genres table automatically.

Note: When you define the ArtistsGenres model, EF will not look at it as a relationship, because you tell him that Hey EF, I have another model named ArtistsGenres! Please manage it for me!!!

Your new entities and dbcontext will be these:

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

}

Let me know if you have any questions or need clarifications on any part.

like image 64
amiry jd Avatar answered Sep 20 '22 16:09

amiry jd