Fließendes NHibernate Selbstreferenzieren von vielen zu vielen
Ich habe eine Entität namens "Bücher", die eine Liste weiterer Bücher mit dem Namen "RelatedBooks" enthalten kann.
Die abgekürzte Book-Entität sieht ungefähr so aus:
public class Book
{
public virtual long Id { get; private set; }
public virtual IList<Book> RelatedBooks { get; set; }
}
So sieht das Mapping für diese Beziehung aus
HasManyToMany(x => x.RelatedBooks)
.ParentKeyColumn("BookId")
.ChildKeyColumn("RelatedBookId")
.Table("RelatedBooks")
.Cascade.SaveUpdate();
Hier ist ein Beispiel für die Daten, die dann in der RelatedBooks-Tabelle generiert werden:
BookId RelatedBookId
1 2
1 3
Das Problem tritt auf, wenn ich versuche, ein Buch zu löschen. Wenn ich das Buch mit der ID 1 lösche, funktioniert alles in Ordnung, und in der RelatedBooks-Tabelle werden die beiden entsprechenden Datensätze entfernt. Wenn ich jedoch versuche, das Buch mit der ID 3 zu löschen, wird der Fehler "Die DELETE-Anweisung ist im Konflikt mit der REFERENCE-Einschränkung" FK5B54405174BAB605 ". Der Konflikt ist in der Datenbank" Test ", Tabelle" dbo.RelatedBooks ", Spalte" RelatedBookId "aufgetreten '".
Grundsätzlich kann das Buch nicht gelöscht werden, da der Datensatz in der RelatedBooks-Tabelle mit der RelatedBookId 3 nie gelöscht wird.
Wie kann ich diesen Datensatz löschen, wenn ich ein Buch lösche?
BEARBEITEN
Nach dem Ändern der Kaskade von SaveUpdate () zu All () besteht das gleiche Problem weiterhin, wenn ich versuche, das Buch mit der ID 3 zu löschen. Auch wenn Cascade auf All () gesetzt ist, wenn das Buch mit der ID 1 gelöscht wird. dann werden alle 3 Bücher (IDs: 1, 2 und 3) gelöscht, so dass auch das nicht funktioniert.
Betrachtet man die SQL, die ausgeführt wird, wenn die Book.Delete () -Methode aufgerufen wird, wenn ich das Buch mit der ID 3 lösche, sieht es so aus, als würde die SELECT-Anweisung die falsche Spalte anzeigen (was meiner Meinung nach bedeutet, dass die SQL-DELETE-Anweisung würde den gleichen Fehler machen, also diesen Datensatz niemals entfernen). Hier ist die SQL für das RelatedBook
SELECT relatedboo0_.BookId as BookId3_
, relatedboo0_.RelatedBookId as RelatedB2_3_
, book1_.Id as Id14_0_
FROM RelatedBooks relatedboo0_
left outer join [Book] book1_ on relatedboo0_.RelatedBookId=book1_.Id
WHERE relatedboo0_.BookId=3
Die WHERE-Anweisung sollte für diesen speziellen Fall ungefähr so aussehen:
WHERE relatedboo0_.RelatedBookId = 3
LÖSUNG
Hier ist, was ich tun musste, um es für alle Fälle zum Laufen zu bringen
Kartierung:
HasManyToMany(x => x.RelatedBooks)
.ParentKeyColumn("BookId")
.ChildKeyColumn("RelatedBookId")
.Table("RelatedBooks");
Code:
var book = currentSession.Get<Book>(bookId);
if (book != null)
{
//Remove all of the Related Books
book.RelatedBooks.Clear();
//Get all other books that have this book as a related book
var booksWithRelated = currentSession.CreateCriteria<Book>()
.CreateAlias("RelatedBooks", "br")
.Add(Restrictions.Eq("br.Id", book.Id))
.List<Book>();
//Remove this book as a Related Book for all other Books
foreach (var tempBook in booksWithRelated)
{
tempBook.RelatedBooks.Remove(book);
tempBook.Save();
}
//Delete the book
book.Delete();
}