Es ist nicht möglich, eine Viele-zu-Viele-Beziehung mit einer benutzerdefinierten Verknüpfungstabelle zu erstellen. In einer Viele-zu-Viele-Beziehung verwaltet EF die Verknüpfungstabelle intern und versteckt. Es ist eine Tabelle ohne Entitätsklasse in Ihrem Modell. Um mit einer solchen Verknüpfungstabelle mit zusätzlichen Eigenschaften zu arbeiten, müssen Sie tatsächlich zwei Eins-zu-Viele-Beziehungen erstellen. Es könnte so aussehen:
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; }
}
Wenn Sie jetzt beispielsweise alle Kommentare von Mitgliedern mit LastName
= "Smith" finden möchten, können Sie eine Abfrage wie folgt schreiben:
var commentsOfMembers = context.Members
.Where(m => m.LastName == "Smith")
.SelectMany(m => m.MemberComments.Select(mc => mc.Comment))
.ToList();
... oder ...
var commentsOfMembers = context.MemberComments
.Where(mc => mc.Member.LastName == "Smith")
.Select(mc => mc.Comment)
.ToList();
Oder um eine Liste der Mitglieder mit dem Namen "Smith" (wir nehmen an, dass es mehr als eines gibt) zusammen mit ihren Kommentaren zu erstellen, können Sie eine Projektion verwenden:
var membersWithComments = context.Members
.Where(m => m.LastName == "Smith")
.Select(m => new
{
Member = m,
Comments = m.MemberComments.Select(mc => mc.Comment)
})
.ToList();
Wenn Sie alle Kommentare eines Mitglieds mit MemberId
= 1 finden möchten :
var commentsOfMember = context.MemberComments
.Where(mc => mc.MemberId == 1)
.Select(mc => mc.Comment)
.ToList();
Jetzt können Sie auch nach den Eigenschaften in Ihrer Join-Tabelle filtern (was in einer Viele-zu-Viele-Beziehung nicht möglich wäre). Beispiel: Filtern Sie alle Kommentare von Mitglied 1 mit einer 99-Eigenschaft Something
:
var filteredCommentsOfMember = context.MemberComments
.Where(mc => mc.MemberId == 1 && mc.Something == 99)
.Select(mc => mc.Comment)
.ToList();
Durch das verzögerte Laden könnten die Dinge einfacher werden. Wenn Sie eine geladen haben Member
, sollten Sie in der Lage sein, die Kommentare ohne eine explizite Abfrage zu erhalten:
var commentsOfMember = member.MemberComments.Select(mc => mc.Comment);
Ich denke, dass das verzögerte Laden die Kommentare automatisch hinter den Kulissen abruft.
Bearbeiten
Nur zum Spaß ein paar Beispiele mehr, wie man Entitäten und Beziehungen hinzufügt und wie man sie in diesem Modell löscht:
1) Erstellen Sie ein Mitglied und zwei Kommentare dieses Mitglieds:
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) Fügen Sie einen dritten Kommentar von member1 hinzu:
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) Erstellen Sie ein neues Mitglied und verknüpfen Sie es mit dem vorhandenen Kommentar2:
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) Erstellen Sie eine Beziehung zwischen vorhandenem Mitglied2 und Kommentar3:
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) Löschen Sie diese Beziehung erneut:
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) Löschen Sie member1 und alle seine Beziehungen zu den Kommentaren:
var member1 = context.Members.Where(m => m.FirstName == "Pete")
.SingleOrDefault();
if (member1 != null)
{
context.Members.Remove(member1);
context.SaveChanges();
}
Dadurch werden auch die Beziehungen gelöscht, MemberComments
da die Eins-zu-Viele-Beziehungen zwischen Member
und MemberComments
und zwischen Comment
und MemberComments
gemäß Konvention mit kaskadierendem Löschen eingerichtet werden. Und dies ist der Fall, weil MemberId
und CommentId
in MemberComment
als Fremdschlüsseleigenschaften für die Member
und Comment
Navigationseigenschaften erkannt werden und da die FK-Eigenschaften vom Typ nicht nullbar sind, ist int
die Beziehung erforderlich, die schließlich das Kaskadierungs-Lösch-Setup verursacht. Sinnvoll in diesem Modell, denke ich.