Переписывание выражения Linq в контексте NHibernate + DDD - PullRequest
0 голосов
/ 25 августа 2011

У меня острый вопрос о преобразовании выражений Linq.У меня был хороший поиск, но я не смог найти ничего, что могло бы охватить этот случай.Я достаточно знаком с Linq, по крайней мере, с точки зрения создания и передачи лямбда-методов в методы, но я немного слабее в вещах Expression.

Во-первых, некоторый контекст: у меня есть универсальное решение по сохранению, основанное на NHibernate, которое используется в ряде проектов DDD.Для особых случаев, когда заданная коллекция дочерних элементов в совокупности может быть по существу бесконечной (т. Е. Очень большой), я не могу просто отобразить набор или сумку, поскольку никогда не будет приемлемо, чтобы вся коллекция была загружена в память.В этой архитектуре код, использующий API, не может напрямую взаимодействовать с репозиторием для выполнения запроса или ограничения результатов таким образом.Конечно, я мог бы вообще не иметь коллекцию в API и предоставлять методы для извлечения соответствующих подмножеств дочерних объектов (а если это не сработает, это то, что я буду делать), но я пытаюсь сделать что-то немного другоеи у меня почти все получилось ...

Эти проекты отображаются с помощью Fluent (не с автоматическим отображением), поэтому я добавил метод в класс базовой карты вform

HasManyQueryable<TCollection>(Expression<Func<T, IQueryable<TCollection>>> memberExpression, Expression<Func<T, TCollection, bool>> selector)

Этот метод извлекает релевантный PropertyInfo из первого Expression (который указывает член для сопоставления).Селектор Expression содержит отношение между родительским и дочерним объектами в качестве замены обычного отображения NHibernate.

Итак, предположим, у меня есть селектор на карте для типа домена User (который является T выше):

HasManyQueryable<Transaction>(x => x.Transactions, (u, t) => t.User == u);

Указывает отображение между подмножеством всех Transactions, где Transaction.User - это предоставленное User u , и свойством User.Transactionsчто IQueryable<Transaction>.Когда создается реальный объект User, мне нужно превратить его в

Expression<Func<Transaction, bool>> expression = (t => t.User == this)

, где this - это строящийся объект User.Другими словами, я хочу взять общее правило, которое говорит, как сопоставить Users с Transactions и превратить его в правило о сопоставлении this User с Transactions.Затем я могу использовать это выражение для генерации IQueryable<Transaction> из репозитория, выполнив запрос Linq, таким образом:

return Repository.For<Transaction>().Where(selector);

Это может работать только тогда, когда селектор равен Func<Transaction, bool>, поэтому моя конечная необходимость состоит в том, чтобыпревратить исходное выражение, которое сгенерирует Func<User, Transaction, bool> в Func<Transaction, bool>.

. Это дает мне коллекцию IQueryable, где все операции запроса выполняются как запросы Linq-to-NHibernate и, таким образом, веськоллекция никогда не загружается в память (да, я знаю, что вы могли бы создать запрос, который фактически заставил бы его это сделать, но я могу перехватить его во время проверки кода).

Фу.Надеюсь, что это имеет смысл.

Кто-нибудь с навыками переписывания leet Expression способен указать мне правильное направление?

1 Ответ

1 голос
/ 25 августа 2011

Честно говоря, я немного растерялся из-за того, что вы пытаетесь сделать с точки зрения домена. Но с точки зрения кода кажется, что все, что вам нужно - это функция с каррированием - метод, который принимает User и создает Func. Примером метода может быть такой, хотя вы можете сделать то же самое встроенным:

Func<Transaction,bool> UserSpecificSelector(User user,
                                            Func<User,Transaction,bool> selector)
{
    return t => selector(user, t);
}

Таким образом, чтобы получить пользовательский селектор, вы должны сделать ...

Func<User, Transaction, bool> selector = // whatever;
User user = //whatever;
Repository.For<Transaction>().Where(t => selector(user, t));

Я сомневаюсь, что вам нужно работать напрямую с иерархией Expression, если вы не реализуете свой собственный поставщик запросов, которым вы не являетесь в этом случае.

...