4

複合 ID が使用されているエンティティがあります。複合 ID を別のキー クラスでラップするコードに変更しました。Linq を使用すると、キー オブジェクトを比較し、Criteria API を使用して Restrictions.IdEq を使用できると思っていましたが、どちらも失敗しました。キー値を明示的に比較して機能させる必要があります。

これが機能するかどうかのドキュメントが見つからないため、現時点では直接比較に固執していますが、これは、キーを変更するときにクエリコードも更新する必要があることを意味しますが、これは明らかに私が望むものではありません。

補足として、NHibernate 3.0.0 Alpha 2 および 3 でこれを試しました。

ドメイン

マッピング

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="Cwc.Pulse.Dal"
                   namespace="Cwc.Pulse.Dal">
  <class name="AddonStatus">
    <composite-id name="Id">
      <key-many-to-one name="Context" column="Context_Id" class="Context" />
      <key-property name="AddonType" column="Addon_Id"/>
    </composite-id>
    <property name="Status" />
  </class>
</hibernate-mapping>

クラス

public class AddonStatus
{
    public virtual string Status { get; set; }
    public virtual Key Id { get; protected set; }

    public AddonStatus()
    {
        Id = new Key();
    }

    public class Key
    {
        public virtual Context Context { get; set; }
        public virtual AddonType AddonType { get; set; }

        public override int GetHashCode()
        {
            return ContextId.GetHashCode() ^ AddonType.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            if (this == obj) return true;
            var o = obj as Key;
            if (null == o) return false;
            return Context == o.Context && AddonType == o.AddonType;
        }
    }
}

ワーキングクエリ

以下のクエリは機能し、ご覧のとおり、キー値を明示的に比較しています。キーオブジェクトは比較しません。

リンク

from status
in session.Query<AddonStatus>()
where status.Id.Context == context && status.Id.AddonType == addonType
select status

基準 API

session.CreateCriteria<AddonStatus>()
.Add(Restrictions.Eq("Id.Context", context))
.Add(Restrictions.Eq("Id.AddonType", addonType))

動作することが期待されますが、動作しません

次のクエリが機能することを期待しています。データベースの代わりにメモリ内のlinqで効率的に実行できますが、クエリでそのような複合IDを処理するのに十分なほど賢く、基準APIが期待されます。

linq と criteria api クエリはどちらも Key オブジェクトの比較を利用します。

var key = new AddonStatus.Key
{
    Context = context,
    AddonType = addonType
};

リンク

from status
in session.Query<AddonStatus>()
where status.Id == key
select status

基準 API

session.CreateCriteria<AddonStatus>()
.Add(Restrictions.IdEq(key))

誰かがそのようなシナリオが機能している場合、私は何が間違っているのでしょうか?

4

2 に答える 2

0

あなたの質問への直接の答えではありませんが、とにかくそれはあなたに役立つかもしれません。AddonStatusを所有者(おそらくコンテキスト)の複合要素としてマッピングすることで、(明示的な)複合キーを回避できます。

  <class name="Context">
    <map name="AddonStates" table="AddonStatus">
      <key column="Context_Id" /> <!-- Foreign key to the Context -->
      <index column="Addon_Id" /> <!-- Dictionary key -->
      <composite-element>
        <property name="Status" /> <!-- data -->
      </composite-element>
    </map>
  </class>

クラスContextでは次のようになります。

class Context
{
  IDictionary<AddonType, AddonStatus> AddonStates { get; private set; }
}

これにより、データベース構造はほぼ同じになりますが、操作方法が異なります。これがあなたが実際に望んでいるものであるかどうかはわかりませんが、それはそれのように見えます。

于 2011-03-09T19:43:56.530 に答える
0

興味深いことに、私は 2.1.2 でこの動作とほぼ正反対の動作をしています。

私のマッピング(簡略化):

<!-- Subscriber class -->
<class name="Subscriber" >
<composite-id name="SubscriberKey" class="SubscriberKey">
  <key-property name="Request" column="RequestID" type="int"/>
  <key-many-to-one name="User" column="UserID" class="User" not-found="ignore" />
</composite-id>

<!-- User class - note that this goes to a different schema, 
  and is not mutable.  Who knows if that's important... -->
<class name="User" schema="AnotherDb.dbo" mutable="false">
<id name="Id" column="UserID" type="int">
  <generator class="native" />
</id>
<property name="FirstName" column="FirstName" type="string" />
<property name="LastName" column="LastName" type="string" />

に行く:

public class User
{
    public virtual int? Id {get; protected set;}
    public virtual string FirstName { get; protected set; }
    public virtual string LastName { get; protected set; }

    public User() { }
}

public class Subscriber
{
    public virtual SubscriberKey SubscriberKey { get; set; }
    public virtual User User { get; set; }

    public Subscriber() { }
}

public class SubscriberKey
{
    public override bool Equals(object obj)
    {
        if (obj is SubscriberKey && obj != null)
            return ((SubscriberKey)obj).Request == Request 
                && ((SubscriberKey)obj).User.Id == User.Id;

        return false;
    }

    public override int GetHashCode()
    {
        return (Request.ToString() + User.Id.ToString()).GetHashCode();
    }

    public virtual int Request { get; set; }
    public virtual User User { get; set; }
    public SubscriberKey() { }
}

機能するもの:

CreateCriteria<Subscriber>()
    .Add(Restrictions.IdEq(keyInstance))
    .UniqueResult<Subscriber>();
CreateCriteria<Subscriber>()
    .Add(Restrictions.Eq("SubscriberKey.User.Id", aUserID))
    .Add(Restrictions.Eq("SubscriberKey.Request", aRequestID))
    .UniqueResult<Subscriber>();

動作しないもの:

Get<Subscriber>(keyInstance);

これは、さまざまな ID 等価クエリ フォーム間の不一致であると考えています。時間ができたら、バグの例として提出する最小限の単体テストを作成します。私はこれについて誰かが持つかもしれないあらゆる/すべての考えに興味があります...


編集:ねえ、私はそれを理解しました!

これを読んだ今、うまくいくもの

Get<Subscriber>(new SubscriberKey() { 
    User = Load<User>(aUserID), // the important part!
    Request = aRequestID
});

これにより、(必要な場合を除いて) データベースにヒットすることなく、User キーのプロキシ オブジェクトが作成されます。にスワップLoad<User>するとGet<User>、遅延読み込みプロパティを尊重するのではなく、すぐにデータベースにアクセスしてオブジェクトを設定します。ロードを使用します。

そして、このようなことこそが、人々が (type)Repository パターンを提案する理由です - 私はこれを舞台裏で行うことができます: Get<>(new SK(){User=Load<>(key.User.Id)}、それでもGet(key)単一のキーによって、他のすべてのオブジェクトと同じです。

于 2011-03-09T03:13:09.717 に答える