2

私がやろうとしていることは本当に非常に単純ですが、NHibernateで正しくマッピングを行うことができないようです。

親オブジェクトと子オブジェクトを含むデータベースに取り組んでいます。子オブジェクトには、データ型Guidの親の主キーへの外部キー参照があります。いずれにせよ、かなり正常です。これで、データベースは外部キーフィールドがnullにならないように設定されているため、親がない孤立したオブジェクトの場合、外部キーは空のGUID( '00000000-0000-0000-0000-000000000000)である必要があります。 ')。

私がNhibernateをセットアップする方法は長い間うまく機能してきましたが、最近、関係を双方向にし、問題が発生し始めました。明らかに、NHibernateは親がnullであることを認識し、nullを外部キーフィールドに保存しようとしますが、それは許可されていません。

私が使用しているリレーションシップマッピングの構造の例を以下に示します。

親側のマッピング:

<id name="ID" column="ID">
    <generator class="guid" />
</id>
<bag name="Children" table="Children" lazy="false" cascade="all" inverse="true">
  <key column="FK_OwnerID" not-null="true"/>
  <one-to-many class="Childclass"/>
</bag>

子側のマッピング:

<many-to-one name="Owner" column="FK_OwnerID" not-found="ignore" not-null="false" class="OwnerClass"/>

私はさまざまなプロパティを試してきましたが、役に立ちませんでした。insert="false"およびupdate="false"プロパティを使用する必要がありますか?使用する場合、関係を正確に維持するにはどうすればよいですか?

助けてくれてありがとう。

4

1 に答える 1

3

私が正しく理解していれば、DB構造は参照整合性を強制していません(FK_OwnerIDは実際には外部キーではありません)が、マッピングの変更を通じて、NHibernateにそれだけを強制するように指示しています。それはうまくいかないと思います。

基本的に、この問題は2つのオプションで解決できると思います。

  1. DBに000-Guidを使用してダミーのエントリを作成します。これは、これらすべての孤立した子の親として機能します。
  2. その列でNULLを許可するようにテーブルを変更し、それを実際の外部キー制約にします(「カスケードでnullを設定する」を使用)(これをお勧めします)。

編集: オプション1がオプションでない場合は、オプション3をお勧めします。NHibernateのインターセプター機能を試すことができます。IInterceptorを実装する(またはEmptyInterceptorから継承する)必要があります。OnSave()メソッドは新しいオブジェクトに使用され、OnFlushDirtyは変更されたオブジェクトに使用されます。ここで行うことは、目的のIDを使用して新しい「仮想」オブジェクトを作成し、それを割り当てることです。

using System;
using NHibernate;

namespace NameSpaceWithDAL
{
    public class TestInterceptor : NHibernate.EmptyInterceptor
    {
        public override bool OnSave(object entity, object id, object[] state, string[] propertyNames, NHibernate.Type.IType[] types)
        {
            if (entity is ChildClass && (entity as ChildClass).Owner == null)
            {
                SetState(propertyNames, state, "Owner", new OwnerClass { ID = "000..." });
            }

            return true;
        }    

        public override bool OnFlushDirty(object entity, object id, object[] currentState, object[] previousState, string[] propertyNames, NHibernate.Type.IType[] types)
        {
            if (entity is ChildClass && (entity as ChildClass).Owner == null)
            {
                SetState(propertyNames, state, "Owner", new OwnerClass { ID = "000..." });
            }

            return true;
        }

        private void SetState(string[] propertyNames, object[] state, string propertyname, object value)
        {
            var index = Array.IndexOf(propertyNames, propertyname);
            if (index == -1) return;
            state[index] = value;
        }    
    }
}

これを使用するには、セッション(OpenSession()内)または全体的な構成のいずれかでインターセプターを定義する必要があります。

new Configuration().SetInterceptor(new TestInterceptor());

上記のコードを単純なプロパティでテストしたので、それが実際にリレーションシップで機能するかどうかはわかりません。

MikeO'Brienからのコード例

于 2011-03-01T12:05:30.823 に答える