9

私は、RelatedBooks という書籍のリストを持つことができる Books というエンティティを持っています。

省略された Book エンティティは次のようになります。

public class Book
{
      public virtual long Id { get; private set; }

      public virtual IList<Book> RelatedBooks { get; set; }
}

この関係のマッピングは次のようになります

HasManyToMany(x => x.RelatedBooks)
                .ParentKeyColumn("BookId")
                .ChildKeyColumn("RelatedBookId")
                .Table("RelatedBooks")
                .Cascade.SaveUpdate();

次に、RelatedBooks テーブルに生成されるデータのサンプルを示します。

BookId     RelatedBookId
1          2
1          3

本を削除しようとすると問題が発生します。ID が 1 の本を削除すると、すべてが正常に機能し、RelatedBooks テーブルから対応する 2 つのレコードが削除されます。ただし、ID が 3 の本を削除しようとすると、「DELETE ステートメントが REFERENCE 制約 "FK5B54405174BAB605" と競合しています。データベース "Test"、テーブル "dbo.RelatedBooks"、列 'RelatedBookId で競合が発生しました」というエラーが表示されます。 」。

基本的に、RelatedBookId が 3 の RelatedBooks テーブルのレコードは削除されないため、Book を削除できません。

本を削除するときにそのレコードを削除するにはどうすればよいですか?

編集

Cascade を SaveUpdate() から All() に変更した後、ID が 3 の Book を削除しようとすると、同じ問題が引き続き発生します。また、Cascade を All() に設定し、ID が 1 の Book を削除すると、次に、3冊すべて(ID:1、2、および3)が削除されるため、それも機能しません。

ID 3 の Book を削除するときに Book.Delete() メソッドが呼び出されたときに実行される SQL を見ると、SELECT ステートメントが間違った列を参照しているように見えます (これは、SQL DELETE ステートメントが同じ間違いを犯す可能性があるため、そのレコードを削除することはありません)。RelatedBook の SQL は次のとおりです。

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

特定のケースでは、WHERE ステートメントは次のようになります。

WHERE relatedboo0_.RelatedBookId = 3

解決

すべてのケースで機能させるために私がしなければならなかったことは次のとおりです

マッピング:

HasManyToMany(x => x.RelatedBooks)
                .ParentKeyColumn("BookId")
                .ChildKeyColumn("RelatedBookId")
                .Table("RelatedBooks");

コード:

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

2 に答える 2

4

カスケード属性を設定するのではなく、本を削除する前に、RelatedBooksコレクションを空にする必要があると思います。

book.RelatedBooks.Clear();
session.Delete(book);

カスケード削除は、関係のもう一方の端にあるオブジェクト(この場合はブック)を削除するため、通常、多対多の関係では実行されません。

于 2010-02-08T15:26:18.317 に答える
0

これはちょうど更新されました:

http://fluentnhibernate.lighthouseapp.com/projects/33236/tickets/115-self-referencing-relationships

于 2010-05-04T16:55:58.287 に答える