LINQ с анонимным классом / свойствами - PullRequest
1 голос
/ 27 июля 2011

Я перевожу проект с работы со стандартными запросами БД на работу с EF и LINQ. У меня есть таблица с определенными записями, которые я буду использовать для создания запроса, который будет выглядеть следующим образом:

select * from client where city = ?

В моей исходной таблице я бы вытащил клиента и город из таблицы, чтобы построить этот запрос.

Также возможно, что клиент и город выше могут быть другой таблицей и / или полем в целом. Как бы я сделал то же самое с EF и LINQ? Это вообще возможно, или мне нужно создать отдельный класс для обработки всей этой логики?

var query = from c in context.clients
            where c.city == ?
            select c;

Редактировать: речь не идет о соединении запросов. Это о создании динамических запросов. Когда я запускаю программу, я не знаю, буду ли я запрашивать данные о городе, адресе или даже о самой таблице «клиент». Это может быть на другом столе. Я хочу иметь возможность динамически создавать запросы.

Ответы [ 5 ]

0 голосов
/ 28 июля 2011

Если вы хотите создавать динамические запросы в Entity Framework, вы МОЖЕТЕ пройти через попытку динамического построения дерева выражений.Однако Entity Framework предоставляет вам несколько дополнительных опций.

Во-первых, EntityObject имеет несколько дополнительных методов Object Services, которые уже позволяют вам построить строку и передать ее непосредственно в число предикатов, включая Where:

c.Customers.Where("City = 'London'");

Если вам нужноСоздавайте большие запросы, включая динамическую настройку источника запросов, рассмотрите возможность использования EntitySQL.Например, с EntitySQL вы можете использовать простой разбор строк и генерировать код, подобный следующему:

string entitySQL = "SELECT VALUE c FROM Customers AS c WHERE c.Address.City = 'Seattle';";
ObjectQuery<Customer> query = context.CreateQuery<Customer>(entitySQL);

Вы можете увидеть обе эти опции в действии в Примерах запросов Entity Framework .

0 голосов
/ 28 июля 2011

Я думаю, что есть несколько подходов, которые вы можете использовать.

Во-первых, вы можете взглянуть на Динамическую библиотеку LINQ (а также посмотреть обновление Дэвида Фаулера здесь).Используя этот подход, вы можете написать свои запросы LINQ следующим образом:

var results = Context.Clients
                .Where("city=='Los Angeles'")
                .OrderBy("address");

Таким образом, ваши предикаты Where и OrderBy являются строками, которые преобразуются в выражения под капотом.

Second, вы можете использовать библиотеку, такую ​​как PredicateBuilder , если вы знаете, к чему обращаетесь, но не уверены, будете ли вы запрашивать одно или несколько полей, например:

var predicate = PredicateBuilder.True<Clients>();
foreach(var criteria in searchCriteria) {
  if (criteria.Key=="city"){
    predicate = predicate.And(c => c.city==criteria.Value);
  } else if (criteria.Key=="address"){
    predicate = predicate.And(c => c.address==criteria.Value);
  }
}
var results = Context.Clients.Where(predicate);

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

Итак, в основном, у вас естьВам доступно несколько вариантов.Библиотека Dynamic LINQ кажется самой простой в использовании, но я никогда не использовал ее, поэтому я не могу точно сказать, насколько она работает и насколько она надежна.Есть также пакет NuGet для библиотеки Dynamic LINQ, если это поможет.

Удачи.Надеюсь, это поможет!

0 голосов
/ 27 июля 2011

вы можете написать запрос, представленный GalacticCowboy, как

var query = from c in context.clients
        join add in context.Addresses on c.AddressID equals add.AddressID
        where addr.city == ?
        select c;

, оба запроса будут генерировать внутреннее соединение, при этом разницы в производительности нет.Разница лишь в том, что если Address является необязательным для клиентов, c.address.City выдаст исключение на клиенте, у которого нет адреса, тогда как этот запрос вернет пустое перечисление

0 голосов
/ 28 июля 2011

Если вы действительно хотите строить свои запросы во время выполнения, то есть пара доступных решений на основе linq - вы можете скомпилировать код во время выполнения во временную сборку или использовать DynamicLinq из одного из примеров MS.

Для получения дополнительной информации см. Вопросы и ответы в: Как создать запрос LINQ из строки?

0 голосов
/ 27 июля 2011

Если ваши таблицы объединены внешними ключами, вы можете получить доступ к значениям в другой таблице с помощью LINQ следующим образом. (Я расширяю ваш пример, предполагая, что есть таблица «адресов» и таблица клиентов имеет внешний ключ к ней.)

var query = from c in context.clients
            where c.address.city == ?
            select c;

Редактировать: (пытаясь понять ваш оригинальный вопрос и последующий комментарий ...)

Я думаю что вы спрашиваете, можете ли вы сделать что-то подобное?

string cityName = "Los Angeles"; // Could be a parameter, etc.

var query = from c in context.clients
            where c.city == cityName
            select c;

Или, чтобы сделать шаг дальше от вашего вопроса, может быть что-то вроде этого:

string cityName = (from c in context.cities
                   where c.id == 5
                   select c.name).FirstOrDefault();

var query = from c in context.clients
            where c.city == cityName
            select c;

Поскольку это IQueryable, вы также можете добавлять дополнительные условия на лету.

if (someCondition)
{
    query = from q in query
            where q.someField >= conditionValue
            select q;
}

Или как угодно. Дерево выражения запроса фактически не будет оцениваться / выполняться до тех пор, пока результаты не потребуются.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...