xkcd
xkcd

Reputation: 2590

Defining many to many relation in code first entity framework

I have 3 classes in my model as you can see below.

[Table("UserProfile")]
public class UserProfile
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    
    public string UserName { get; set; }

    public ICollection<MartialArtUserProfile> MartialArtUserProfiles { get; set; }
}

[Table("MartialArt")]
public class MartialArt
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public string Name { get; set; }

    public string Description { get; set; }

    public string IconPath { get; set; }

    public string ImagePath { get; set; }

    public ICollection<MartialArtUserProfile> MartialArtUserProfiles { get; set; }
}

public class MartialArtUserProfile
{
    public int UserProfileId { get; set; }
    public UserProfile UserProfile { get; set; }

    public int MartialArtId { get; set; }
    public MartialArt MartialArt { get; set; }
}

And I have a configuration class for many to many relationship as below:

public class MartialArtUserProfileConfiguration : EntityTypeConfiguration<MartialArtUserProfile>
{
    public MartialArtUserProfileConfiguration()
    {
        HasKey(a => new { a.MartialArtId, a.UserProfileId });

        HasRequired(a => a.MartialArt)
            .WithMany(s => s.MartialArtUserProfiles)
            .HasForeignKey(a => a.MartialArtId)
            .WillCascadeOnDelete(false);

        HasRequired(a => a.UserProfile)
            .WithMany(p => p.MartialArtUserProfiles)
            .HasForeignKey(a => a.UserProfileId)
            .WillCascadeOnDelete(false);
    }
}

After defining my entities an relation when I try to run Update-Database in Package Manager Console, it says:

One or more validation errors were detected during model generation:

\tSystem.Data.Entity.Edm.EdmEntityType: : EntityType 'MartialArtUserProfile' has no key defined. Define the key for this EntityType. \tSystem.Data.Entity.Edm.EdmEntitySet: EntityType: EntitySet 'MartialArtUserProfiles' is based on type 'MartialArtUserProfile' that has no keys defined.

What am I doing wrong?

Thanks in advance,

Upvotes: 5

Views: 9646

Answers (3)

Grayson
Grayson

Reputation: 191

If I understand you are simply trying to create a many to many with a transitive table. If so this is another way to approach this. Use Fluent API to map as below. You can change the UserProfileToMartialArt to whatever you want the table name to be. Instead of creating the MartialArtUserProfile model let EF create the middle ground for you. This also specifies your keys which should get you around the error.

modelBuilder.Entity<UserProfile>()
    .HasMany(b => b.MartialArts)
    .WithMany(a => a.UserProfiles)
    .Map(m => m.MapLeftKey("MartialArtId")
        .MapRightKey("UserProfileId")
        .ToTable("UserProfileToMartialArt"));

In MartialArts Model put

public IList<UserProfile> UserProfiles { get; set; }   

In UserProfile Model put

public IList<MartialArt> MartialArts { get; set; }  

Upvotes: 8

Rob Church
Rob Church

Reputation: 6943

In EntityFramework 6.1, you don't need to do any of this - just add collections of the two types to each class and everything falls into place.

public class UserProfile {
    public int Id { get; set; }
    public string UserName { get; set; }
    public virtual ICollection<MartialArt> MartialArts { get; set; }

    public UserProfile() {
        MartialArts = new List<MartialArt>();
    }
}

public class MartialArt {
    public int Id { get; set; }
    public string Name { get; set; }
    // *snip*
    public virtual ICollection<UserProfile> UserProfiles { get; set; }

    public MartialArt() {
        UserProfiles = new List<UserProfile>();
    }
}

Upvotes: 6

Admir Tuzović
Admir Tuzović

Reputation: 11177

Try doing it like this:

[Table("UserProfile")]
public class UserProfile
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public string UserName { get; set; }

    [InverseProperty("UserProfiles")]
    public IList<MartialArt> MartialArts { get; set; }
}

[Table("MartialArt")]
public class MartialArt
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public string Name { get; set; }

    public string Description { get; set; }

    public string IconPath { get; set; }

    public string ImagePath { get; set; }

    [InverseProperty("MartialArts")]
    public IList<UserProfile> UserProfiles { get; set; }
}

Upvotes: 7

Related Questions