1

nHibernate と QueryOver を使用して List() のジェネリック メソッドを作成したいと考えています。結合を追加したいところまで来ましたが、結合しているジェネリック型を指定しないとできないと思います...すべてのジェネリックを宣言する必要があるため、それほど動的にはなりません。結合の動的リストを持っている場所はありますか? 以下のコード:

public static IList<T> QueryOver<T>(
        Dictionary<Expression<Func<T, object>>, JoinType> joins,
        List<Expression<Func<T, bool>>> predicates,
        Dictionary<Expression<Func<T, object>>, System.Web.UI.WebControls.SortDirection> sortList,
        int? maxResults
    ) where T : class
    {
        IList<T> results;
        IQueryOver<T, T> query;

        results = null;

        // open the session
        using (ISession session = OpenSession())
        {
            // begin a transaction
            using (ITransaction transaction = session.BeginTransaction())
            {
                try
                {
                    // declare the query
                    query = session.QueryOver<T>();

                    // joins
                    if (joins != null && joins.Count > 0)
                    {
                        foreach (KeyValuePair<Expression<Func<T, object>>, JoinType> join in joins)
                        {
                            // required to specify the type in the format query.JoinQueryOver<SubType>(join.Key, join.Value)
                            // BUT this means that it's not so dynamic because each SubType would have to be specified in the method call, yes?
                            query = query.JoinQueryOver(join.Key, join.Value);
                        }
                    }

                    // apply the where clauses
                    if (predicates != null && predicates.Count > 0)
                    {
                        foreach (Expression<Func<T, bool>> predicate in predicates)
                        {
                            query = query.Where(predicate);
                        }
                    }

                    // apply the sorting
                    if (sortList != null && sortList.Count > 0)
                    {
                        foreach (KeyValuePair<Expression<Func<T, object>>, System.Web.UI.WebControls.SortDirection> sort in sortList)
                        {
                            if (sort.Value == System.Web.UI.WebControls.SortDirection.Ascending)
                            {
                                query = query.OrderBy(sort.Key).Asc;
                            }
                            else
                            {
                                query = query.OrderBy(sort.Key).Desc;
                            }
                        }
                    }

                    // max results
                    if (maxResults.HasValue && maxResults.Value > 0)
                    {
                        query = (IQueryOver<T, T>)query.Take(maxResults.Value);
                    }

                    results = query.List();

                    // no errors, commit the transaction
                    transaction.Commit();
                }
                catch (Exception ex)
                {
                    // error, rollback
                    transaction.Rollback();

                    // throw the exception and let the business logic deal with it
                    throw ex;
                }
            }
        }

        return results;
    }
4

1 に答える 1

1

JoinQueryOver の代わりに JoinAlias を使用することを検討してください...それはあなたを助けるはずです。

結合には、タイプ T のエンティティに対する直接結合と、間接結合 (2 つ以上のステップ) の 2 種類があります。これらには異なるアプローチが必要です。

(1) 直接結合の場合、メソッドはタイプの IEnumerable を受け取ることができます (準備完了):

Tuple<Expression<Func<T, object>>, Expression<Func<object>>>

その例は、呼び出しコードで次のようになります。

JoiningEntity joiningEntity = null;
new Tuple<Expression<Func<YourEntityType, object>>, Expression<Func<object>>>(entity => entity.JoiningEntity, () => joiningEntity)

null オブジェクトは、QueryOver が解決できるようにするための単なるエイリアスです。null であることを示す Visual Studio の警告に腹を立てるかもしれないので、ヘルパー メソッドを使用して null オブジェクトを作成しますNull.Get<HolidayOccupancyPrice>()(Null ヘルパー メソッドについては下部を参照)。

(2) 間接結合の場合、次のタイプの IEnumerable を渡す必要があります。

Tuple<Expression<Func<object>>, Expression<Func<object>>>

つまり、上記と同じですが、エンティティ タイプはありません。そして、呼び出しコードは次のような結合を送信する場合があります。

JoiningEntity joiningEntity = null;
new Tuple<Expression<Func<object>>, Expression<Func<object>>>(() => joiningEntity.IndirectJoiningEntity, () => joiningEntity)

クエリ メソッドでまとめると、次のようになります。

IEnumerable<Tuple<Expression<Func<T, object>>, Expression<Func<object>>>> directJoins;
IEnumerable<Tuple<Expression<Func<object>>, Expression<Func<object>>>> indirectJoins;
// ....
foreach (var join in directJoins)
    query = queryable.Left.JoinAlias(dependency.Item1, dependency.Item2);
foreach (var join in indirectJoins)
    query = queryable.Left.JoinAlias(dependency.Item1, dependency.Item2);

(明示的に左結合を指定したことに注意してください。これを制御可能にしたい場合は、タプルの追加パラメーターとして追加する必要があります)

これですべてが非常に複雑に見えますが、一度組み立てるとかなり簡単です。もちろん、ヘルパー メソッドを作成して、コード内の「Func」ガンクの量を減らすことができます。

それが役立つことを願っています!


Null ヘルパー メソッド:

public static class Null
{
    public static T Get<T>()
    {
        return default(T);
    }
}
于 2011-03-04T19:52:17.657 に答える