質問

現在、NHibernateをデータアクセスレイヤーとして使用し、Fluent NHibernateを使用してマッピングファイルを作成しています。 TripItemとTripItemAttributeValueの2つのクラスがあり、それらの間には多対多の関係があります。

マッピングは次のとおりです。

public class TripItemMap : ClassMap<TripItem2>
{
    public TripItemMap()
    {
        WithTable("TripItemsInt");
        NotLazyLoaded();

        Id(x => x.ID).GeneratedBy.Identity().WithUnsavedValue(0);
        Map(x => x.CreateDate, "CreatedOn").CanNotBeNull();
        Map(x => x.ModifyDate, "LastModified").CanNotBeNull();

        /* snip */

        HasManyToMany<TripItemAttributeValue>(x => x.Attributes).AsBag()
            .WithTableName("TripItems_TripItemAttributeValues_Link")
            .WithParentKeyColumn("TripItemId")
            .WithChildKeyColumn("TripItemAttributeValueId")
            .LazyLoad();
    }
}

public class TripItemAttributeValueMap : ClassMap<TripItemAttributeValue>
{
    public TripItemAttributeValueMap()
    {
        WithTable("TripItemAttributeValues");

        Id(x => x.Id).GeneratedBy.Identity();
        Map(x => x.Name).CanNotBeNull();

        HasManyToMany<TripItem2>(x => x.TripItems).AsBag()
            .WithTableName("TripItems_TripItemAttributeValues_Link")
            .WithParentKeyColumn("TripItemAttributeValueId")
            .WithChildKeyColumn("TripItemId")
            .LazyLoad();
    }
}

アプリケーションのある時点で、データベースから既存の属性を取得し、それらをtripItem.Attributesに追加してから、tripItemオブジェクトを保存します。最終的に、TripItems_TripItemAttributeValues_Linkは新しいレコードを取得しないため、リレーションが保持されなくなります。

それが役立つ場合、これらはこれらのクラスに対してFluent NHibernateによって生成されたマッピングファイルです。

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="true" assembly="ETP.Core" namespace="ETP.Core.Domain">
  <class name="TripItem2" table="TripItemsInt" xmlns="urn:nhibernate-mapping-2.2" lazy="false">
    <id name="ID" column="ID" type="Int32" unsaved-value="0">
      <generator class="identity" />
    </id>
    <property name="CreateDate" column="CreatedOn" type="DateTime" not-null="true">
      <column name="CreatedOn" />
    </property>
    <property name="ModifyDate" column="LastModified" type="DateTime" not-null="true">
      <column name="LastModified" />
    </property>
    <bag name="Attributes" lazy="true" table="TripItems_TripItemAttributeValues_Link">
      <key column="TripItemId" />
      <many-to-many column="TripItemAttributeValueId" class="ETP.Core.Domain.TripItemAttributeValue, ETP.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    </bag>
  </class>
</hibernate-mapping>

and

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="true" assembly="ETP.Core" namespace="ETP.Core.Domain">
  <class name="TripItemAttributeValue" table="TripItemAttributeValues" xmlns="urn:nhibernate-mapping-2.2">
    <id name="Id" column="Id" type="Int32">
      <generator class="identity" />
    </id>
    <property name="Name" column="Name" length="100" type="String" not-null="true">
      <column name="Name" />
    </property>
    <bag name="TripItems" lazy="true" table="TripItems_TripItemAttributeValues_Link">
      <key column="TripItemAttributeValueId" />
      <many-to-many column="TripItemId" class="ETP.Core.Domain.TripItem2, ETP.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    </bag>
  </class>
</hibernate-mapping>

ここで何が間違っているのですか?

役に立ちましたか?

解決

@efdee

私は同じ問題を抱えていて、これにほぼ2日間を費やしました。多対多の関係があり、リンクテーブルも更新されていませんでした。私はNHibernateを初めて使います。それを学ぼうとしているので、私が言うすべてを一粒の塩で取ります。

まあ、それはFluent NHibernateでもマッピングでもないことがわかりましたが、私はNHibernateが多対多でどのように機能するかを理解していません。多対多の関係では、両方のエンティティのコレクションにデータが入力されていない場合、NHibernateはリンクテーブルにデータを永続化しません。

このエンティティが多対多の関係にあるとしましょう:


partial class Contact
{
   public string ContactName {get; set;}
   public IList Locations {get; set;}

}

partial class Location
{
   public string LocationName {get; set;}
   public string LocationAddress {get;set;}
   public IList Contacts {get;set;}
}

Contact.Locationsに場所を追加するとき、location.Contacts内にも連絡先が存在することを確認する必要があります。

場所を追加するために、Contactクラス内にこのメソッドがあります。


public void AddLocation(Location location)
        {
            if (!location.Contacts.Contains(this))
            {
                location.Contacts.Add(this);
            }
            Locations.Add(location);
        }

これで問題は解決したようですが、NHibernateを取り上げて学習していると言ったように、もっと良い方法があるかもしれません。より良い解決策があれば、投稿してください。

これは、両方のコレクションを確認するように指示した投稿です。 http://www.coderanch.com/t/217138/Object-Relational-Mapping/link-table-of-ManyToMany-annotation

他のヒント

Session.Flush()を呼び出すか、トランザクションを使用します。

Fluent NHibernateでどのように実行するのかわかりませんが、バッグ( TripItems )のカスケードオプションを設定する必要があります。いつものように、 Ayendeには、カスケードオプションに関する有用な投稿があります

簡単なGoogleから、試してみることをお勧めします:

HasManyToMany<TripItem2>(x => x.TripItems).AsBag()
        .WithTableName("TripItems_TripItemAttributeValues_Link")
        .WithParentKeyColumn("TripItemAttributeValueId")
        .WithChildKeyColumn("TripItemId")
        .LazyLoad()
/*-->*/ .Cascade.All(); /*<-- this is the bit that should make it work */

私も同じ問題を抱えていました-多対多の結合データは保持されませんでした。別の多対1の関係からマッピングをコピーしました(多対多のrelに変更しました)が、inverse =&quot; true&quot;を保持しました。属性。この属性を削除すると、問題は解決しました。

David Kempが正しい:バッグにカスケードを追加したい。

私は常にマッピングファイルを手動で編集(および手動で作成)しているので、私の自然な傾向はそこに置くことです。次のようにできます:

<bag name="TripItems" lazy="true" table="TripItems_TripItemAttributeValues_Link" cascade="all">
  <key column="TripItemAttributeValueId" />
  <many-to-many column="TripItemId" class="ETP.Core.Domain.TripItem2, ETP.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</bag>

クラスを「純粋」に保ち、.hbm.xmlファイルでnHibernateに関連するすべてのものを保持することで、ソリューションがよりきれいに保たれることがわかりました。そのようにして、使用したい新しいORMソフトウェアがある場合、マッピングファイルを置き換えるだけで、クラスを書き換えません。ユニットテストを使用してクラスをテストし、xmlにテスト容易性を与えますが、Fluent NHibernateのメソッドのようなものを実行します。

まったく同じ問題を抱えていますが、NHibernate.JetDriverを使用しています。成功せずに推奨された回答を使用してみました。 NHibernate.JetDriverに多対多に関して制限があるかどうかは誰にもわかりますか?

誰かがたまたまそれらのレビューに興味を持っている場合の私のhbmファイルは次のとおりです。

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Ace.Docs.Core.Domain" assembly="Ace.Docs.Core">
<class name="Ace.Docs.Core.Domain.Address, Ace.Docs.Core" table="Addresses" lazy="true">
    <id name="Id" column="ID">
        <generator class="identity" />
    </id>
    <property name="Address1" column="Address1" />
    <property name="Address2" column="Address2" />
    <property name="City" column="City" />
    <property name="EmailAddress" column="EmailAddress" />
    <property name="Phone1" column="Phone1" />
    <property name="Phone2" column="Phone2" />
    <property name="PostalCode" column="PostalCode" />
    <property name="StateOrProvince" column="StateOrProvince" />
    <many-to-one name="AddressTypeMember" column="AddressTypeID" class="AddressType" />
    <bag name="HasPersonalInfo" table="Link_PersonalInfo_Addresses" lazy="true" cascade="save-update" inverse="true" >
        <key column="AddressID"></key>
        <many-to-many column="PersonalInfoID" class="PersonalInfo" />
    </bag>
</class>

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Ace.Docs.Core.Domain" assembly="Ace.Docs.Core">
<class name="Ace.Docs.Core.Domain.PersonalInfo, Ace.Docs.Core" table="PersonalInfo" lazy="true">
    <id name="Id" column="ID">
        <generator class="identity" />
    </id>
    <property name="Prefix" column="Prefix" />
    <property name="FirstName" column="FirstName" />
    <property name="MiddleName" column="MiddleName" />
    <property name="LastName" column="LastName" />
    <property name="SIN" column="SIN" />
    <property name="Birthdate" column="Birthdate" />
    <property name="Note" column="Notes" />
    <bag name="HasAddress" table="Link_PersonalInfo_Addresses" lazy="true" cascade="save-update" inverse="true" >
        <key column="PersonalInfoID"></key>
        <many-to-many column="AddressID" class="Address" />
    </bag>
</class>

私はそれを手に入れ、これが他の誰かに役立つことを願っています。問題は、両方のバッグでinverse = 'true'があったことです。以下の抜粋を読むと、バッグの1つだけで逆にtrueに設定する必要があることに注意してください。

inverse =&quot; true&quot;の使用に注意してください。繰り返しますが、この設定はカテゴリコレクションへの変更を無視し、関連付けと反対側のアイテムコレクションをデータベースと同期する表現として使用するようNHibernateに指示します。

Cascade.All()は私の問題の解決策ではないのではないかと心配しています。私が試したものの1つでした。問題は、コレクションに追加されたアイテムが保存されないことではなく、コレクションに追加された時点で既にデータベースに存在していることです。リンクテーブルのエントリが作成されていないだけです。さらに、Cascade.All()によって子アイテムも削除されると思いますが、これは私のシナリオでは望ましくない動作です。 Cascade.SaveUpdate()を使用してみましたが、指摘したように、これは本当に私の問題ではない何かを解決します:-)

ただし、念のため、このソリューションを再試行し、結果をお知らせします。

クラスを純粋に保つという点では、これはFluent NHibernateの場合の100%です。作成するクラスマッピングは、.hbm.xmlファイルとほぼ同じように、エンティティクラスと並んでいるC#コードファイルです。

私もこれに苦労していましたが、トラブルのまったく別の理由で来ました。私の例では、多対多のリレーションシップを持たないオブジェクトがある場合、saveOrUpdateを呼び出すだけで十分です。ただし、多対多の関係がある場合は、saveOrUpdate呼び出しがBeginTransactionおよびCommitTransaction内にあることを確認する必要がありました。流なNhibernateを初めて使用するので、これが明らかな場合は謝罪します。しかし、私にはそうではありませんでした。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top