2011-07-01 11 views
0

NHibernate 3 introduced the With clause Criteria API用。私はそれを使用して、多対多関係の結合を制限しようとしています.Hibernateは、正しいテーブルではなく、リンクテーブルに追加の結合制限を適用しています。Criteria API多対多関係のWith節

PlayerとAddressの間に多対多の関係があり、Playerとその郵送先住所をAddress.IsMailingAddressに制限して返信したいと考えています。 Restricting IsMailingAddress where句では、メールアドレスを持たないレコード(またはアドレスがまったくない)は返されません。そのため、結合でそれを制限する必要があります。以下のコードは簡略化されており、HQLを使用することはできません。

クエリ:

var target = session.CreateCriteria<Player>() 
    .SetProjection(Projections.Property("PlayerId")) 
    .CreateAlias("Addresses", "ad", JoinType.LeftOuterJoin, Restrictions.Eq("ad.IsMailingAddress", true)) 
    .Add(Restrictions.Eq("LastName", "Anonymous")) 
    .List(); 

は、SQLを生成します。

SELECT this_.PlayerId as y0_ 
FROM dbo.VPlayerExisting this_ 
     left outer join dbo.LinkPlayAddr addresses3_ 
     on this_.PlayerId = addresses3_.PlayerId 
      and (ad1_.MailingAddressFlag = 1 /* @p0 */) 
     left outer join dbo.VAddress ad1_ 
     on addresses3_.AddressId = ad1_.AddressId 
      and (ad1_.MailingAddressFlag = 'Anonymous' /* @p1 */) 
WHERE this_.Name_Last = @p2 

はMailingAddressFlag(IsMailingAddressにマッピングされています列が)そうでない多対多のリンクテーブルに制限されていますAddressテーブルへの結合でLastName制限が適用されます。クエリは発行されますが、もちろんデータベースサーバは例外を発生させます。

これはバグですか、サポートされていないのですか、間違っていますか?

+0

これはバグだと思いますが、簡単な回避策が見つかりました。木の森を見ることができる最初の人に25ポイント。ヒント:プレーヤーは複数のアドレスにリンクすることができますが、それらのアドレスの1つだけが郵送先アドレスです。 –

答えて

1
var target = session.CreateCriteria<Player>() 
    .CreateAlias("Addresses", "ad", JoinType.InnerJoin) 
    .Add(Restrictions.Eq("LastName", "Anonymous")) 
    .Add(Restrictions.Eq("ad.IsMailingAddress",true)) 
    .List(); 

IsMailingAddressの制限付きで郵送先住所に参加するだけですか?

MailingAddressのアドレスとそのアドレスを持つプレイヤー(LastNameが "Anonymous"の場合)をIsMailingAddressとして返します。

+0

アドレスがないか、IsMailingAddressが設定されているアドレスがない場合、これはプレーヤーを返しません。最初の問題(行がない)は、左結合で簡単に解決され、2番目の問題は難しくなります。目標は、郵送先住所があればそれを返すこと、それ以外の場合はヌル住所を返すことです。 –

+0

プレイヤーは、郵送先住所としてマークされていない単一の住所を持つことができますか? –

+0

あなた自身の質問に答えることができますので、あなたの回避策を理解できますか? –

0

解決策は次のとおりです。 IsMailingAddressが設定されているアドレスは1つだけにする必要があります。そのため、条件が成立すると、内部結合を使用するかどうかを判断できます。

var target = session.CreateCriteria<Player>() 
    .SetProjection(Projections.Property("PlayerId")) 
    .CreateAlias("Addresses", "ad", JoinType.InnerJoin) 
    .Add(RestrictionsOr(Restrictions.Eq("ad.IsMailingAddress", true), Restrictions.IsNull("ad.AddressId"))) 
    .Add(Restrictions.Eq("LastName", "Anonymous")) 
    .List(); 
+0

あなたはどのDBを使用していますか? SQLをポストすることができますか? –