2017-03-14 18 views
1

Nhibernateを使用してプロジェクトを開発するためにリポジトリパターンを使用しています。 Nhibernateで複雑な結合を行う方法。私は以下のリポジトリメソッドを使用してデータを取得しています。NHibernateを使用してリポジトリパターンで複合結合を行う方法は?

public virtual TEntity FindBy(Expression<Func<TEntity, bool>> query) 
    { 
     try 
     { 
      return NHUnitOfWork.Session.Query<TEntity>().Where(query).FirstOrDefault(); 
     } 
     catch (Exception ex) 
     { 
      throw; 
     } 
    } 

ここでは、結合なしでデータをフェッチできます。結合でデータをフェッチする方法 例:メニューの詳細はメニューテーブルに保存され、メニュー権限はメニュー権限テーブルに保存されます。そのためのリポジトリを作成するには?

答えて

1

QueryOverと入力すると、FindByメソッドにExpressionの代わりに入力Junctionを受け入れることになります。

次のコードが参考になる場合があります。必要がない場合はcolumnListtopパラメータを削除します。私のISessionの使用方法が違うことに注意してください。 nhSessionNHUnitOfWork.Sessionに置き換える必要があります。もう1つの違いは、Queryを使用し、QueryOverを使用していることです。

public virtual IList<T> FindBy<T>(ProjectionList columnList, Junction where, int top) where T : BaseEntity 
{ 
    IList<T> instance = GetQueryOver<T>(columnList, where).Take(top).List(); 
    return instance; 
} 

public virtual IQueryOver<T> GetQueryOver<T>(ProjectionList columnList, Junction where) where T : BaseEntity 
{ 
    IQueryOver<T> query = null; 
    if((columnList != null) && (where != null)) 
    { 
     query = nhSession.QueryOver<T>() 
       .Select(columnList) 
       .TransformUsing(Transformers.AliasToBean<T>()) 
       .Where(where); 
    } 
    else if((columnList != null) && (where == null)) 
    { 
     query = nhSession.QueryOver<T>() 
       .Select(columnList) 
       .TransformUsing(Transformers.AliasToBean<T>()); 
    } 
    else if((columnList == null) && (where != null)) 
    { 
     query = nhSession.QueryOver<T>() 
       .Where(where); 
    } 
    else 
    { 
     query = nhSession.QueryOver<T>(); 
    } 
    return query; 
} 

そして、あなたのようないくつかの他の場所でこれを呼び出すことができます。あなたが熱心な負荷関連企業に、FetchFetchManyを使用したい場合は

Junction where = Restrictions.Conjunction(); 
where.Add(Restrictions.Eq(Projections.Property<MyEntity>(x => x.Field), findValue)); 
where.Add(Restrictions.................); 
where.Add(Restrictions.................); 
entityList = Repository.FindBy<MyEntity>(null, where, 100); 
+1

この回答はこの質問を対象としていますか?彼は 'QueryOver'ではなく' Query'を使用しており、トランスフォーマーは必要ありません。彼はAutoMapperの 'Select'や' ProjectTo'を使って投影を簡単にすることができます。 – Rabban

1

public virtual Menu FindBy(Expression<Func<Menu, bool>> query) 
{ 
    return NHUnitOfWork.Session.Query<Menu>().Where(query) 
     .FetchMany(m => m.Rights) 
     // Required with FetchMany and First, otherwise only one right would be loaded. 
     .ToList() 
     .FirstOrDefault(); 
} 

またはあなたのモデルはメニューごとに1つだけの権利がある場合:

public virtual Menu FindBy(Expression<Func<Menu, bool>> query) 
{ 
    return NHUnitOfWork.Session.Query<Menu>().Where(query) 
     .Fetch(m => m.Right) 
     .FirstOrDefault(); 
} 

をしかし、あなたには、いくつかの「一般的なリポジトリ」のNHibernateのAPIをカプセル化を定義したいようです。たぶん、その後

public virtual TEntity FindBy<TFetched>(Expression<Func<TEntity, bool>> query, 
    Expression<Func<TEntity, TFetched>> fetch) 
{ 
    var query = NHUnitOfWork.Session.Query<TEntity>().Where(query); 
    if (fetch != null) 
     query = query.Fetch(fetch); 
    return query 
     .FirstOrDefault(); 
} 

しかし、あなたは多くのフェッチを*必要な場合はどのように行うには:

public virtual TEntity FindBy<TFetched>(Expression<Func<TEntity, bool>> query, 
    Expression<Func<TEntity, IEnumerable<TFetched>>> fetchMany) 
{ 
    var query = NHUnitOfWork.Session.Query<TEntity>().Where(query); 
    if (fetchMany != null) 
     query = query.FetchMany(fetchMany); 
    return query 
     // Required with FetchMany and First, otherwise only one right would be loaded. 
     .ToList() 
     .FirstOrDefault(); 
} 

またはあなたのモデルはメニューごとに1つだけの権利を持っている場合

?サブフェッチ( ThenFetch/ ThenFetchMany)?それは私に呪われた道のように見える。あなたは、そのパスに続くNHibernate全体のカプセル化をコード化するかもしれません。

実際に、Expression where引数をリポジトリに公開しても、私にはよく見えません。リポジトリは、データのクエリ方法を定義する責任を負いません。
あなたがそれをしたいのであれば、IQueryableを直接公開してみませんか?この "リポジトリ"の外側でクエリを定義しながら、 "リポジトリ"にカプセル化しようとするよりもコードが冗長であることがはるかに少なくなります。

*:複数の場合に備えてデカルト製品にご注意くださいFetchMany。これを避けるには、クエリを複数に分割するか(1回のDBへのラウンドトリップを希望する場合はToFutureを使用)、またはフェッチするのではなくlazy loading with batchingを使用します。

関連する問題