LINQ к объектам, сгенерированным sql - PullRequest
6 голосов
/ 23 февраля 2009

У меня проблемы с linq для сущностей в структуре сущностей ado.net. В основном то, что я делаю, это:

var results = (from c in companies
    where c.Name.StartsWith(letter)
    select c);

и это переводится в SQL как что-то вроде:

WHERE (CAST(CHARINDEX(@p, [Extent1].[Name]) AS int)) = 1

это нормально, но в моей таблице миллионы записей, поэтому она работает ОЧЕНЬ медленно. То, что мне нужно, чтобы сгенерировать это что-то вроде:

WHERE Name LIKE @p + '%'

Я искал все выше и ниже и не могу найти никаких решений, кроме как использовать хранимую процедуру или использовать сущность sql ...

Есть ли способ сделать это через linq? Возможно, каким-то образом расширив linq до сущностей провайдера linq, или каким-то образом перехватывая дерево команд или сгенерированный запрос?

Ответы [ 6 ]

3 голосов
/ 24 февраля 2009

Я не эксперт по SQL, но думаю, что оба синтаксиса:

ГДЕ (CAST (CHARINDEX (@p, [Extent1]. [Имя]) AS int)) = 1

и

ГДЕ Имя НРАВИТСЯ @p + '%'

приведет к сканированию таблицы или, в идеале, к сканированию индекса. Итог они будут выполнять одинаково. Я проверил это, просмотрев планы выполнения ниже. В итоге, вам нужно переосмыслить схему базы данных или то, как вы выполняете поиск. Это не проблема LINQ.

Одна из возможных областей для улучшения: убедитесь, что вы проиндексировали столбец, по которому вы ищете.

альтернативный текст http://download.binaryocean.com/plan1.gif

альтернативный текст http://download.binaryocean.com/plan2.gif

2 голосов
/ 23 февраля 2009

Ого, это действительно странный способ сделать это! Обратите внимание, что LINQ-to-SQL (в данном случае) использует LIKE @p0 + '%' ... очень странно.

Какой провайдер EF (база данных) вы используете? SQL Server?

Как вы говорите, хранимая процедура будет работать, но вам не нужно иметь для этого ... очень, очень странно ...

1 голос
/ 30 апреля 2009

Это известная проблема с Linq to Entities. В отличие от LIKE, очевидно, эта конструкция не использует индексы.

Мы добились некоторого успеха, используя Substring (что переводится как SUBSTRING). План выполнения аналогичен, но в нашем случае запрос выполняется гораздо быстрее.

Это еще одно "Я уверен, что это будет исправлено в EF 2" ...: - (

0 голосов
/ 24 июля 2015

Вы можете очень легко использовать реальный лайк в Link to Entities

Вот что нужно, чтобы это заработало:

Добавить

    <Function Name="String_Like" ReturnType="Edm.Boolean">
      <Parameter Name="searchingIn" Type="Edm.String" />
      <Parameter Name="lookingFor" Type="Edm.String" />
      <DefiningExpression>
        searchingIn LIKE lookingFor
      </DefiningExpression>
    </Function>

к вашему EDMX в этом теге:

EDMX: EDMX / EDMX: Продолжительность / EDMX: ConceptualModels / Schema

Также запомните пространство имен в атрибуте <schema namespace="" />

Затем добавьте класс расширения в указанное выше пространство имен:

public static class Extensions
{
    [EdmFunction("DocTrails3.Net.Database.Models", "String_Like")]
    public static Boolean Like(this String searchingIn, String lookingFor)
    {
        throw new Exception("Not implemented");
    }
}

Этот метод расширения теперь сопоставляется с функцией EDMX.

Подробнее здесь: http://jendaperl.blogspot.be/2011/02/like-in-linq-to-entities.html

0 голосов
/ 26 февраля 2009

Я попытался использовать этот синтаксис вместо

Name.Substring(0, 1) == "E"

Этот SQL генерируется

WHERE N'E' = (SUBSTRING([Name], 0 + 1, 1))

Может быть, это более эффективно?

0 голосов
/ 25 февраля 2009

Является ли «буква» символом? Если вы сделали это строкой, что произойдет?

var results = (from c in companies
    where c.Name.StartsWith(letter.ToString())
    select c);
...