5

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,

2
  • do you really need the MartialArtUserProfile class or you are just using it to make the many-to-many relationship ? Commented Mar 10, 2013 at 23:43
  • I'm just using it to make the many-to-many relationship. @Sniffer Commented Mar 11, 2013 at 9:38

3 Answers 3

8

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; }  
Sign up to request clarification or add additional context in comments.

1 Comment

I've gotten review feedback, that using .Map in fluent to define the relationship above, was not the best practice, as the solution could be compiled after a change, and it wouldn't be until runtime that this is evident. Would you suggest using Reflection, or some other means (off the top of my head, assigning the entities table attribute and the mapping to constant?)
7

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

8 Comments

This works well for me. Although I am in a scenario where I care that only one entity be linked to the other. Is that possible using this? At first I just had a IList<OtherEntityType> Others {get;set;} but it wasn't working correctly
Are you talking about 1 to 1 relationship?
I'm talking about a (one-way) many-many relationship... by one-way I mean in my code I want one navigational property. This isn't a big deal at all, I'm just wondering about the how, if possible
That could be done with intermediate class that would be mapped to many-to-many table on the database. With the code above, many-to-many table is built by EF, but you can't reach it from the code. However you might redesign code so that you have a class that has foreign keys to both MartialArts and UserProfiles, but is considered to be entity of it's own, that is used as many-to-many link. With that scenario, it's possible to accomplish what you're trying to do.
@GusCrawford By convention.
|
6

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

3 Comments

Awesome, worked for me. This is how it should be. Go 6.1
If this is an evolution of Admir's answer above ( stackoverflow.com/a/15328042/489396) and the 'falling into place' is based on convention, what conventions are required between the map table?
@GusCrawford - The mapping table is kept completely hidden from your code, it will be created simply by having two collections of the opposite object in your code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.