Динамическое объединение nHibernate с QueryOver - PullRequest
1 голос
/ 21 января 2011

Я хочу создать универсальный метод для List () с nHibernate и QueryOver.Я дошел до того, что хотел добавить объединения, но не думаю, что смогу без указания универсального типа, к которому присоединяюсь ... Что не делает его таким динамичным, потому что каждый универсальный должен быть объявлен.Есть ли где-нибудь динамический список объединений?Код ниже:

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 Ответ

1 голос
/ 04 марта 2011

Изучите использование 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)

Нулевой объект - это просто псевдоним, чтобы QueryOver мог разрешить его. Вы можете раздражаться из-за предупреждений в Visual Studio о том, что оно пустое, поэтому я бы использовал вспомогательный метод для создания пустых объектов, например, 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» в вашем коде.

Надеюсь, это поможет!


Нулевой вспомогательный метод:

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