Подтвердить что ты не робот

Преобразование выражения LINQ в текст SQL без контекста DB

Либо LINQ to SQL, либо LINQ to Entities уже имеют возможность конвертировать LINQ в текстовую строку SQL. Но я хочу, чтобы мое приложение выполняло преобразование без использования контекста db, что, в свою очередь, означает активное соединение с базой данных, которое требуется обоим этим провайдерам.

Я хотел бы преобразовать выражение LINQ в эквивалентную строку SQL для предложений WHERE и ORDER BY, без зависимости от контекста БД, чтобы сделать следующий интерфейс репозитория:

public interface IStore<T> where T : class 
{
     void Add(T item);
     void Remove(T item);
     void Update(T item);
     T FindByID(Guid id);

     //sure could use a LINQ to SQL converter!
     IEnumerable<T> Find(Expression<Func<T, bool>> predicate);
     IEnumerable<T> FindAll();
}

Вопрос

Это прежде всего обход дерева и преобразование, которое меня интересует. Кто-нибудь знает о существующей библиотеке (nuget?), которую я могу включить для использования в таком настраиваемом контексте?

Как я уже создал свой собственный рабочий инструмент LINQ, преобразованный в текст SQL, аналогично этому дереву выражений к примеру SQL который работает в моем выше хранилище. Это позволяет мне писать код следующим образом:

IRepository<Person> repo = new PersonRepository();
var maxWeight = 170;
var results = repo.Find(x => (x.Age > 40 || x.Age < 20) && x.Weight < maxWeight);

Но мой код и этот пример являются примитивными (и этот пример сам полагается на контекст db LINQ to SQL). Например, не обрабатывать генерацию операторов "LIKE".

Я не ожидаю и не нуждаюсь в генератор-инструменте, который обрабатывает каждый мыслимый запрос LINQ. Например, я не беспокоюсь о том, как обрабатывать и генерировать объединения или включать. Фактически, с другими ~ 20 часами мой собственный пользовательский код может охватывать все случаи, о которых я беспокоюсь (в основном, инструкции "WHERE" и "ORDER BY" ).

Но в то же время я чувствую, что мне не нужно писать собственный код для этого. Если я застрял писать свои собственные, то мне все равно будет интересно, если кто-то может указать мне на определенные классы, которые я могу отразить и подражать (NHibernate, EF и т.д.). Я спрашиваю о том, какие конкретные классы заглядывают, если вы их знаете, потому что я не хочу часами просеивать код массивного инструмента, чтобы найти нужную мне часть.

Не важно, но если кто-то хочет знать, почему я не просто использую LINQ to SQL или LINQ для Entities... для моего конкретного приложения я просто предпочитаю использовать такой инструмент, как Dapper.

ИСПОЛЬЗОВАНИЕ CASES Независимо от того, завершу ли я сам инструмент или найду стороннюю библиотеку, вот почему полезно использовать "текстовую строку LINQ to SQL":

  • Тип предиката я в метод IRepository.Find имеет intellisense и базовую проверку времени компиляции.
  • Мой предлагаемый интерфейс IStore может быть реализован для доступа к БД или доступа к веб-сервисам. Чтобы уточнить, если я могу преобразовать предикат LINQ "WHERE/ORDER BY" в предложение SQL "WHERE/ORDER BY", то...
    • Строка SQL может использоваться непосредственно Dapper.
    • Строка SQL, в отличие от выражения LINQ, может быть отправлена ​​в службу WCF, которая будет использоваться для прямого доступа к БД (который сам по себе не может использовать Dapper).
    • Строка SQL может быть десериализована, с настраиваемый код, обратно в оператор LINQ службой WCF. Эрик Липперт комментирует это.
  • Пользовательский интерфейс может использовать механику IQueryable для динамического создания предиката для предоставления репозиторию

Короче говоря, такой инструмент помогает реализовать понятие хранилища "спецификация" или "запрос объекта" в соответствии с DDD и делает это, не принимая зависимость от EF или LINQ to SQL.

4b9b3361

Ответ 1

Это то, что я кратко рассмотрел довольно давно. Вы можете посмотреть http://iqtoolkit.codeplex.com/ и/или http://expressiontree.codeplex.com/ для идей. Как уже упоминалось другими, построение поставщика запросов Linq далеко не тривиально, если вы не ограничиваете область действия минимальным набором функций, которые вам действительно нужны.

Если ваши цели связаны с понятием репозиториев "спецификация" или "запрос объекта" в соответствии с DDD, это может оказаться не лучшим решением. Вместо CRUD, подобных абстракциям, связанным с технологией, может быть более продуктивным сосредоточиться на способах выражения поведения домена с минимальными прямыми зависимостями от абстракций, связанных с технологией. Как недавно обсуждал Эрик Эванс, он сожалеет о том, что основное внимание уделяется техническим строительным блокам, таким как хранилища, в его первоначальных описаниях DDD.

Ответ 2

Выполнение этого правильно очень сложно, особенно если прямо сейчас вы мало что знаете о деревьях выражений (это то, что IQueryable использует для представления запросов).

Но если вы действительно хотите начать (или просто получить представление о том, как много будет работать), взгляните на серию Matt Warren 17-series Создание поставщика IQueryable.

Ответ 3

Я могу подтвердить, что это довольно большой объем работы, который подходит только для самых опытных разработчиков .NET. Отличное знание С#, опыт работы с несколькими языками, включая T-SQL, обязательно. Нужно хорошо разбираться как в С# (или VB.NET), так и в T-SQL, поскольку они должны писать переводчик, используя первый в последний. Кроме того, это относится к области метапрограмм, которая считается довольно развитой отраслью информатики. Существует много абстрактного мышления. Слои абстрактных концепций сложены друг на друга.

Если все это не является барьером, то это упражнение может быть довольно приятным и полезным, по крайней мере, в первый месяц или около того. Одна из распространенных проблем в этих провайдерах я заметил, что негибкость и сомнительные варианты дизайна вначале привели к трудностям и хакерским исправлениям и т.д. Планируя как можно больше заранее, четко понимая весь процесс, разные этапы, компоненты, правильно идентифицирующие слои и проблемы могли бы значительно облегчить его развитие. Самая большая ошибка, которую я видел в одном провайдере, заключалась в том, что - не удалось сломать выходной запрос в его части - выберите, от, где и порядок. Каждая часть должна быть представлена ​​ее собственным объектом повсюду, а затем складываться в конце. Я объясняю этот подход в своем сквозном учебнике о том, как написать поставщика в серии, приведенной ниже. Theres образец проекта включен, с упрощенным/учебным вариантом и полной версией, сделанной с нуля для проекта. Нахождение времени, чтобы написать об этом было проблемой само по себе.