2011-01-04 14 views
0

エンティティの1対多の関係を照会したいと思います。Nhibernate - Linqと1対多数の関係を照会

public class UserMap : ClassMap<User> { 
    public UserMap() { 
     Table("Users"); 
     Id(x => x.UserID); 
     HasMany(x => x.Membership) 
      .KeyColumn("UserID") 
      .Inverse() 
      .Cascade.All(); 
    } 
} 

public class MembershipMap : ClassMap<Membership> { 
    public MembershipMap() { 
     Table("Membership"); 
     Id(x => x.MembershipID); 
     References(x => x.User); 
     Map(x => x.StartDate); 
     Map(x => x.DaysLeft) 
      .Formula("CASE WHEN EndDate IS NOT NULL AND dbo.DayDiff(GETUTCDATE(), EndDate) > 0 THEN dbo.DayDiff(GETUTCDATE(), EndDate) ELSE 0 END"); 
      // DayDiff is a udf which gets the number of days between two dates 
     Map(x => x.IsValid) 
      .Formula("CASE WHEN dbo.GetValidMembershipID(UserID) = MembershipID THEN 1 ELSE 0 END"); 
      // GetValidMembershipID is a udf which works out the valid membership id for this user 
    } 
} 
次流暢マッピング(マッピングは一種の無関係です、私は唯一の指導のためにここにこれを入れている)で

public class User { 
    public virtual int UserID { get; set; } 

    public virtual Membership CurrentMembership { 
     get { return Membership.Single(m => m.IsValid); } 
    } 

    public virtual IList<Membership> Membership { get; private set; } 

    public User() { 
     Membership = new List<Membership>(); 
    } 
} 

public class Membership { 
    public virtual int MembershipID { get; set; } 
    public virtual User User { get; set; } 
    public virtual DateTime StartDate { get; set; } 
    public virtual DateTime? EndDate { get; set; } 
    public virtual int DaysLeft { get; set; } 
    public virtual bool IsValid { get; set; } 

    public Membership() { 
    } 
} 

:さらに私の問題を説明するために、想像私のアプリケーションは、以下のエンティティを持っています

ご覧のとおり、ユーザーは多数のメンバーシップを持つことができます。 CurrentMembership(ユーザーに対するプロパティ)は、IsValidプロパティがtrueのユーザーに対してメンバシップを返します(これは、ユーザーに対する単一のメンバシップにのみ該当します)。

現在、現在のメンバーシップが20日以内に残っているすべてのユーザーを取得したいと考えています。

私の最初の試みが言っていた:

session.Linq<User>().Where(u => u.CurrentMembership.DaysLeft < 20).ToList(); 

しかし、これはエラー投げた:

"プロパティを解決できませんでした:のCurrentMembership:ユーザー"

をこれは一種のI以来、期待されましたこのプロパティのフォーミュラマッピングを使用しませんでした(メンバーシップに対するDaysLeftおよびIsValidプロパティの場合と同じように)。文字列、int、およびboolをマッピングする以外の数式マッピングを使用する方法がわかりません。次の私が言ってみました:

session.Linq<User>().Where(u => u.Membership.Single(m => m.IsValid).DaysLeft < 20).ToList(); 

しかし、これはエラー投げた:「オブジェクトのインスタンスに設定されていないオブジェクト参照」

私はこのメンバーシップを直接照会することができますが、私はこれを多くの場所で行う例として使っています。私はLinqでそれをクエリすることができますCurrentMembershipプロパティをマッピングする別の方法を提案することができます。最適なパフォーマンスが必要なので、リストに変換してメモリで作業するだけでは十分ではないことに注意してください。

私は助けていただきありがとうございます。ありがとう

答えて

0

NHibernate 2.1のNHibernateContribで古いLINQプロバイダを使用しています。 このプロバイダーは現在サポートされていません。

NHibernate 3.0構文に組み込まれたLINQプロバイダはsession.Linq<TEntity>()の代わりにsession.Query<TEntity>()です。

NHibernate 3.0は最終リリースですので、これまで問題があった場合は既に解決されている可能性があります。私は重いクエリの両方を使用し、新しいクエリは多くのシナリオを満たします。
おそらく、最新のトランクソースを取得して使用するのが最善です。

NHiberrate 3.0であなたのものを交換することを強くお勧めします。 Hibernate 2.1と "ほぼ" 100%後方互換性があり、変更する必要があるのはすべてsession.Linq<TEntity>()からsession.Query<TEntity>()までです。

まだ動作しない場合は、whereの条件でu.Membership.Single(...)の代わりにu.Membership.Any(...)またはu.Membership.First(...)を試すことができます。

これでも解決しない場合は、クエリを元に戻してください。 Membershipを照会し、membership.Userを選択してください。

CurrentMembershipはマップされていないため動作しません。

+1

新しいLinqプロバイダはごみです。多くの問題がありますが、最大の理由は、Skip/Takeの前にFetchを呼び出すことができないということです。これらが解決されるまで、私はアップグレードする立場にはいません。 – nfplee

+1

あなたはQueryOver APIを試しましたか?これはNH 3.0用の私のデフォルトAPIです。 LINQと非常によく似ていますが、Criteria APIの大部分の機能(それを囲むラッパー)を備えています。残念なことに、古いLINQはデッドエンドです。そのような制限は固定されません。 – Meligy

+0

QueryOverは有望そうですが、私はLinqの柔軟性が好きです。将来的に私のアプリケーションをエンティティフレームワークにアップグレードしたい場合は、これは簡単なことです。私は今は古いプロバイダに固執することに決めましたが、NHibernate 3またはEntity Frameworkにアップグレードする予定がある場合は、かなりの痛みはないように、私は単体テストを作成しています。 – nfplee

関連する問題