2011-02-01 10 views
5

1対多関係のあるテーブルでISession.Deleteを実行しようとするとNHibernateでエラーが発生します。Fluent NHibernate MappingがAllDeleteOrphanに設定されていますが、まだDB内の外部キーをnullにしようとしています

NHibernateは、子テーブルの行を単に削除するのではなく、子テーブルの親テーブルへの外部キーをnullに設定しようとしています。ここで

は自分のドメインです:

public class Parent 
{ 

    public Parent() 
    { 
     _children = new List<Child>(); 
    } 

    public int Id { get; set; } 
    public string SimpleString { get; set; } 
    public DateTime? SimpleDateTime { get; set; } 

    private IList<Child> _children; 
    public IEnumerable<Child> Children 
    { 
     get { return _children; } 
    } 
    public void AddChild(Child child) 
    { 
     child.Parent = this; 
     _children.Add(child); 
    } 
} 


public class Child 
{ 
    public int Id { get; set; } 
    public string SimpleString { get; set; } 
    public DateTime? SimpleDateTime { get; set; } 
    [JsonIgnore] 
    public Parent Parent { get; set; } 
} 

私がセットアップしている流暢NHibernateのマッピングを次のように

public class ParentMap : ClassMap<Parent> 
{ 
    public ParentMap() 
    { 
     Not.LazyLoad(); 
     Id(x => x.Id); 
     Map(x => x.SimpleString); 
     Map(x => x.SimpleDateTime); 

     HasMany(x => x.Children) 
      .Not.LazyLoad() 
      .KeyColumn("ParentId").Cascade.AllDeleteOrphan() 
      .Access.ReadOnlyPropertyThroughCamelCaseField(Prefix.Underscore); 

    } 
} 

public class ChildMap : ClassMap<Child> 
{ 
    public ChildMap() 
    { 
     Not.LazyLoad(); 
     Id(x => x.Id); 
     Map(x => x.SimpleString); 
     Map(x => x.SimpleDateTime); 
     References(x => x.Parent).Not.Nullable().Column("ParentId").Cascade.All().Fetch.Join(); 
    } 
} 

私はCascade.AllDeleteOrphan()にNHibernateのを指示しましたが、まだParentIdはを設定しようとしていますforiegnキーがnullに設定されているのは、私が設定したテストです:

public void Delete_GivenTableWithChildren_WillBeDeletedFromDB() 
{ 
    int id; 
    using (var createSession = MsSqlSessionProvider.SessionFactory.OpenSession()) 
    { 
     var parent = new Parent(); 
     parent.AddChild(new Child { SimpleString = "new child from UI" }); 

     using (var trx = createSession.BeginTransaction()) 
     { 
      createSession.Save(parent); 
      trx.Commit(); 
      id = parent.Id; 
     } 
    } 

    using (var firstGetSession = MsSqlSessionProvider.SessionFactory.OpenSession()) 
    { 
     var result = firstGetSession.Get<Parent>(id); 
     Assert.IsNotNull(result); 
    } 

    using (var deleteSession = MsSqlSessionProvider.SessionFactory.OpenSession()) 
    { 
     using (var trx = deleteSession.BeginTransaction()) 
     { 
      deleteSession.Delete("from " + typeof(Parent).Name + " o where o.Id = :Id", id, NHibernateUtil.Int32); 
      trx.Commit(); 
     } 
    } 

    using (var session = MsSqlSessionProvider.SessionFactory.OpenSession()) 
    { 
     var result = session.Get<Parent>(id); 
     Assert.IsNull(result); 
    } 
} 

exec sp_executesql N'UPDATE [Child] SET ParentId = null WHERE ParentId = @p0',N'@p0 int',@p0=5 

:以下のSQLを試みた後のn deleteSession.Deleteライン

NHibernate.Exceptions.GenericADOException : could not delete collection: [SaveUpdateOrCopyTesting.Parent.Children#5][SQL: UPDATE [Child] SET ParentId = null WHERE ParentId = @p0] 
    ----> System.Data.SqlClient.SqlException : Cannot insert the value NULL into column 'ParentId', table 'SaveUpdateCopyTestingDB.dbo.Child'; column does not allow nulls. UPDATE fails. 
The statement has been terminated. 

誰もが、私は私のマッピングで間違って何をやったか知っている、またはしようとするからNHibernateのを停止する方法を知っています外部キーのIDをnullにしますか?

おかげ

デイブ

答えて

19

はParentMapのhasManyの上.Inverse()を設定してみてください、それは次のようになります。

HasMany(x => x.Children) 
     .Not.LazyLoad() 
     .KeyColumn("ParentId").Cascade.AllDeleteOrphan().Inverse() 
     .Access.ReadOnlyPropertyThroughCamelCaseField(Prefix.Underscore); 
+0

伝説..ありがとうございました.. Inverseは、Parentレコードに挿入する前にChildレコードに挿入しようとすると、Savesが失敗することを意味すると考えました。ちょうど完全に実行されたクルードのテストとすべてのカスケードは、扱います..ありがとう:) – CraftyFella

+1

喜んで助けてください。それは良い説明に役立つ場合は、逆の使用上のまともなSOスレッドがあります:http://stackoverflow.com/questions/1061179/when-to-use-inverse-false-on-nhibernate-hibernate-onetomany-relationships – nkirkes

+0

それは動作します元気? –

0

私はあなたがHQLを削除する場合はカスケードが動作するかどうかはわかりません。

はこれを試してみてください:

var parent = deleteSession.Load<Parent>(id) 
deleteSession.Delete(parent); 

それはあなたが遅延ロードを持っていないのは残念です。 Loadは、エンティティをデータベースから読み取る必要がないため、メモリ内にプロキシを作成するだけです。

+0

こんにちは、上記を試してみましたが、それが最終的に提起されている同じ制約例外で、その結果、以前と同じSQL文を生成しますDBによって。 "カラム 'ParentId'、テーブル 'SaveUpdateCopyTestingDB.dbo.Child'にNULLを挿入できません;カラムはNULLを許可しません。 他のアイデアはありますか? – CraftyFella

関連する問題