Non è possibile creare una relazione molti-a-molti con una tabella di join personalizzata. In una relazione molti-a-molti EF gestisce la tabella di join internamente e nascosta. È una tabella senza una classe Entity nel tuo modello. Per lavorare con una tabella di join di questo tipo con proprietà aggiuntive, dovrai creare in realtà due relazioni uno-a-molte. Potrebbe apparire così:
public class Member
{
public int MemberID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual ICollection<MemberComment> MemberComments { get; set; }
}
public class Comment
{
public int CommentID { get; set; }
public string Message { get; set; }
public virtual ICollection<MemberComment> MemberComments { get; set; }
}
public class MemberComment
{
[Key, Column(Order = 0)]
public int MemberID { get; set; }
[Key, Column(Order = 1)]
public int CommentID { get; set; }
public virtual Member Member { get; set; }
public virtual Comment Comment { get; set; }
public int Something { get; set; }
public string SomethingElse { get; set; }
}
Se ora desideri trovare tutti i commenti dei membri con LastName
= "Smith", ad esempio, puoi scrivere una query come questa:
var commentsOfMembers = context.Members
.Where(m => m.LastName == "Smith")
.SelectMany(m => m.MemberComments.Select(mc => mc.Comment))
.ToList();
... o ...
var commentsOfMembers = context.MemberComments
.Where(mc => mc.Member.LastName == "Smith")
.Select(mc => mc.Comment)
.ToList();
Oppure per creare un elenco di membri con il nome "Smith" (supponiamo che ce ne sia più di uno) insieme ai loro commenti è possibile utilizzare una proiezione:
var membersWithComments = context.Members
.Where(m => m.LastName == "Smith")
.Select(m => new
{
Member = m,
Comments = m.MemberComments.Select(mc => mc.Comment)
})
.ToList();
Se vuoi trovare tutti i commenti di un membro con MemberId
= 1:
var commentsOfMember = context.MemberComments
.Where(mc => mc.MemberId == 1)
.Select(mc => mc.Comment)
.ToList();
Ora puoi anche filtrare in base alle proprietà nella tabella dei join (che non sarebbe possibile in una relazione molti-a-molti), ad esempio: Filtra tutti i commenti del membro 1 che hanno una proprietà 99 Something
:
var filteredCommentsOfMember = context.MemberComments
.Where(mc => mc.MemberId == 1 && mc.Something == 99)
.Select(mc => mc.Comment)
.ToList();
A causa del caricamento lento, le cose potrebbero diventare più facili. Se hai caricato Member
, dovresti essere in grado di ottenere i commenti senza una query esplicita:
var commentsOfMember = member.MemberComments.Select(mc => mc.Comment);
Immagino che il caricamento lento recupererà automaticamente i commenti dietro le quinte.
modificare
Solo per divertimento qualche esempio in più su come aggiungere entità e relazioni e come eliminarle in questo modello:
1) Crea un membro e due commenti di questo membro:
var member1 = new Member { FirstName = "Pete" };
var comment1 = new Comment { Message = "Good morning!" };
var comment2 = new Comment { Message = "Good evening!" };
var memberComment1 = new MemberComment { Member = member1, Comment = comment1,
Something = 101 };
var memberComment2 = new MemberComment { Member = member1, Comment = comment2,
Something = 102 };
context.MemberComments.Add(memberComment1); // will also add member1 and comment1
context.MemberComments.Add(memberComment2); // will also add comment2
context.SaveChanges();
2) Aggiungi un terzo commento di member1:
var member1 = context.Members.Where(m => m.FirstName == "Pete")
.SingleOrDefault();
if (member1 != null)
{
var comment3 = new Comment { Message = "Good night!" };
var memberComment3 = new MemberComment { Member = member1,
Comment = comment3,
Something = 103 };
context.MemberComments.Add(memberComment3); // will also add comment3
context.SaveChanges();
}
3) Crea un nuovo membro e collegalo al commento2 esistente:
var comment2 = context.Comments.Where(c => c.Message == "Good evening!")
.SingleOrDefault();
if (comment2 != null)
{
var member2 = new Member { FirstName = "Paul" };
var memberComment4 = new MemberComment { Member = member2,
Comment = comment2,
Something = 201 };
context.MemberComments.Add(memberComment4);
context.SaveChanges();
}
4) Creare una relazione tra membro2 esistente e commento3:
var member2 = context.Members.Where(m => m.FirstName == "Paul")
.SingleOrDefault();
var comment3 = context.Comments.Where(c => c.Message == "Good night!")
.SingleOrDefault();
if (member2 != null && comment3 != null)
{
var memberComment5 = new MemberComment { Member = member2,
Comment = comment3,
Something = 202 };
context.MemberComments.Add(memberComment5);
context.SaveChanges();
}
5) Cancella di nuovo questa relazione:
var memberComment5 = context.MemberComments
.Where(mc => mc.Member.FirstName == "Paul"
&& mc.Comment.Message == "Good night!")
.SingleOrDefault();
if (memberComment5 != null)
{
context.MemberComments.Remove(memberComment5);
context.SaveChanges();
}
6) Elimina membro1 e tutte le sue relazioni con i commenti:
var member1 = context.Members.Where(m => m.FirstName == "Pete")
.SingleOrDefault();
if (member1 != null)
{
context.Members.Remove(member1);
context.SaveChanges();
}
Questo elimina anche le relazioni MemberComments
perché le relazioni uno-a-molti tra Member
e MemberComments
e tra Comment
e MemberComments
sono impostate con eliminazione a cascata per convenzione. E questo è il caso perché MemberId
e CommentId
in MemberComment
vengono rilevati come proprietà di chiave esterna per le proprietà di navigazione Member
e Comment
e poiché le proprietà FK sono di tipo non nullable int
, è necessaria una relazione che alla fine provoca il collegamento a cascata-cancellazione-installazione. Ha senso in questo modello, penso.