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

考虑使用 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.Get<HolidayOccupancyPrice>()(请参阅底部的空辅助方法)。

(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”垃圾的数量。

希望有帮助!


空辅助方法:

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