nHibernate动态加入QueryOver

时间:2011-01-21 04:06:05

标签: c# nhibernate list generics queryover

我想用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;
    }

1 个答案:

答案 0 :(得分:1)

使用JoinAlias代替JoinQueryOver ...这应该对你有用。

有两种类型的连接:类型T实体上的直接连接和间接连接(两个或多个步骤)。这些需要不同的方法。

(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可以解析它。您可能会对Visual Studio中的警告感到恼火,告诉您它是null,因此我将使用辅助方法来创建空对象,例如Null.Get<HolidayOccupancyPrice>()(参见Null helper方法的底部)。

(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);

(注意我明确指定了Left join - 如果你想要这个可控制的,你必须将它作为元组中的附加参数添加)

现在所有看起来都很复杂,但是一旦你把它放在一起就相当直接。您当然可以创建辅助方法来减少代码中“Func”的数量。

希望有所帮助!


空助手方法:

public static class Null
{
    public static T Get<T>()
    {
        return default(T);
    }
}