I have this scenario:
public class Member
{
public int MemberID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
}
public class Comment
{
public int CommentID { get; set; }
public string Message { get; set; }
public virtual ICollection<Member> Members { get; set; }
}
public class MemberComment
{
public int MemberID { get; set; }
public int CommentID { get; set; }
public int Something { get; set; }
public string SomethingElse { get; set; }
}
How do I configure my association with fluent API? Or is there a better way to create the association table?
It's not possible to create a many-to-many relationship with a customized join table. In a many-to-many relationship EF manages the join table internally and hidden. It's a table without an Entity class in your model. To work with such a join table with additional properties you will have to create actually two one-to-many relationships. It could look like this:
If you now want to find all comments of members with
LastName
= "Smith" for example you can write a query like this:...or...
Or to create a list of members with name "Smith" (we assume there is more than one) along with their comments you can use a projection:
If you want to find all comments of a member with
MemberId
= 1:Now you can also filter by the properties in your join table (which would not be possible in a many-to-many relationship), for example: Filter all comments of member 1 which have a 99 in property
Something
:Because of lazy loading things might become easier. If you have a loaded
Member
you should be able to get the comments without an explicite query:I guess that lazy loading will fetch the comments automatically behind the scenes.
Edit
Just for fun a few examples more how to add entities and relationships and how to delete them in this model:
1) Create one member and two comments of this member:
2) Add a third comment of member1:
3) Create new member and relate it to the existing comment2:
4) Create relationship between existing member2 and comment3:
5) Delete this relationship again:
6) Delete member1 and all its relationsships to the comments:
This deletes the relationships in
MemberComments
too because the one-to-many relationships betweenMember
andMemberComments
and betweenComment
andMemberComments
are setup with cascading delete by convention. And this is the case becauseMemberId
andCommentId
inMemberComment
are detected as foreign key properties for theMember
andComment
navigation properties and since the FK properties are of type non-nullableint
the relationship is required which finally causes the cascading-delete-setup. Makes sense in this model, I think.TLDR; (semi-related to an EF editor bug in EF6/VS2012U5) if you generate the model from DB and you cannot see the attributed m:m table: Delete the two related tables -> Save .edmx -> Generate/add from database -> Save.
For those who came here wondering how to get a many-to-many relationship with attribute columns to show in the EF .edmx file (as it would currently not show and be treated as a set of navigational properties), AND you generated these classes from your database table (or database-first in MS lingo, I believe.)
Delete the 2 tables in question (to take the OP example, Member and Comment) in your .edmx and add them again through 'Generate model from database'. (i.e. do not attempt to let Visual Studio update them - delete, save, add, save)
It will then create a 3rd table in line with what is suggested here.
This is relevant in cases where a pure many-to-many relationship is added at first, and the attributes are designed in the DB later.
This was not immediately clear from this thread/Googling. So just putting it out there as this is link #1 on Google looking for the issue but coming from the DB side first.
@Esteban, the code you provided is right, thanks, but incomplete, I've tested it. There are missing properties in "UserEmail" class:
I post the code I've tested if someone is interested. Regards
I want to propose a solution where both flavors of a many-to-many configuration can be achieved.
The "catch" is we need to create a view that targets the Join Table, since EF validates that a schema's table may be mapped at most once per
EntitySet
.This answer adds to what's already been said in previous answers and doesn't override any of those approaches, it builds upon them.
The model:
The configuration:
The context:
From Saluma's (@Saluma) answer
This still works...
...but could now also be...
This still works...
...but could now also be...
If you want to remove a comment from a member
If you want to
Include()
a member's commentsThis all feels like syntactic sugar, however it does get you a few perks if you're willing to go through the additional configuration. Either way you seem to be able to get the best of both approaches.
Excellent answer by Slauma.
I'll just post the code to do this using the fluent API mapping.
On your
DbContext
derived class you could do this:It has the same effect as the accepted answer, with a different approach, which is no better nor worse.
EDIT:
I've changed CreatedDate from bool to DateTime.EDIT 2: Due to lack of time I've placed an example from an application I'm working on to be sure this works.
One way to solve this error is to put the
ForeignKey
attribute on top of the property you want as a foreign key and add the navigation property.Note: In the
ForeignKey
attribute, between parentheses and double quotes, place the name of the class referred to in this way.