2009-12-08 6 views
7

Следующая LINQ заявление:Почему этот запрос LINQ-to-SQL получает исключение NotSupportedException?

public override List<Item> SearchListWithSearchPhrase(string searchPhrase) 
{ 
    List<string> searchTerms = StringHelpers.GetSearchTerms(searchPhrase); 

    using (var db = Datasource.GetContext()) 
    { 
     return (from t in db.Tasks 
       where searchTerms.All(term => 
        t.Title.ToUpper().Contains(term.ToUpper()) && 
        t.Description.ToUpper().Contains(term.ToUpper())) 
       select t).Cast<Item>().ToList(); 
    } 
} 

дает мне эту ошибку :

System.NotSupportedException: Локальная последовательность не может быть использован в LINQ к SQL реализации операторов запроса за исключением оператор Contains().

Глядя вокруг него, кажется, мой единственный вариант, чтобы получить все мои детали первый в общий список, а затем сделать запрос LINQ на этом.

Или есть умный способ перефразировать вышеуказанный оператор LINQ-to-SQL, чтобы избежать ошибки?

ОТВЕТ:

Благодаря Рэнди, ваша идея помогла мне построить следующее решение. Это не изящно, но оно решает проблему, и поскольку это будет сгенерировано кодом, я могу обработать до, например, 20 поисковых терминов без дополнительной работы:

public override List<Item> SearchListWithSearchPhrase(string searchPhrase) 
{ 
    List<string> searchTerms = StringHelpers.GetSearchTerms(searchPhrase); 

    using (var db = Datasource.GetContext()) 
    { 

     switch (searchTerms.Count()) 
     { 
      case 1: 
       return (db.Tasks 
        .Where(t => 
         t.Title.Contains(searchTerms[0]) 
         || t.Description.Contains(searchTerms[0]) 
         ) 
        .Select(t => t)).Cast<Item>().ToList(); 
      case 2: 
       return (db.Tasks 
        .Where(t => 
         (t.Title.Contains(searchTerms[0]) 
         || t.Description.Contains(searchTerms[0])) 
         && 
         (t.Title.Contains(searchTerms[1]) 
         || t.Description.Contains(searchTerms[1])) 
         ) 
        .Select(t => t)).Cast<Item>().ToList(); 
      case 3: 
       return (db.Tasks 
        .Where(t => 
         (t.Title.Contains(searchTerms[0]) 
         || t.Description.Contains(searchTerms[0])) 
         && 
         (t.Title.Contains(searchTerms[1]) 
         || t.Description.Contains(searchTerms[1])) 
         && 
         (t.Title.Contains(searchTerms[2]) 
         || t.Description.Contains(searchTerms[2])) 
         ) 
        .Select(t => t)).Cast<Item>().ToList(); 
      default: 
       return null; 
     } 
    } 
} 
+0

Обратите внимание, что это не ошибка «не реализована», это ошибка «локальная последовательность не может быть использована». – Lucas

+0

спасибо, исправлено, что –

+0

Я не уверен, правильно ли я это читаю, много скобок, но я не вижу хорошо сформированного предложения where. Ваш поискTerms.All() возвращает список строк, которые не образуют предложение where, следовательно, ошибка. – Lazarus

ответ

1

Эд, я столкнулся с подобной ситуацией. Код ниже. Важная строка кода - это где я устанавливаю переменную memberList. Посмотрите, подходит ли это вашей ситуации. Извините, если форматирование не получилось хорошо.

Рэнди

// Get all the members that have an ActiveDirectorySecurityId matching one in the list. 
IEnumerable<Member> members = database.Members 
    .Where(member => activeDirectoryIds.Contains(member.ActiveDirectorySecurityId)) 
    .Select(member => member); 

// This is necessary to avoid getting a "Queries with local collections are not supported" 
//error in the next query.  
memberList = members.ToList<Member>(); 

// Now get all the roles associated with the members retrieved in the first step. 
IEnumerable<Role> roles = from i in database.MemberRoles 
    where memberList.Contains(i.Member) 
    select i.Role; 
+0

Извините, Рэнди, но вы пропустили этот пункт. – Lazarus

1

Поскольку вы не можете присоединиться к местной последовательности с Linq таблицы, единственный способ перевести приведенный выше запрос в SQL woluld заключается в создании ИНЕКЕ, как многие LIKE условиях, существуют элементы в списке searchTerms (объединены с операторами И). По-видимому, linq не делает этого автоматически и вместо этого выбрасывает. Но это может быть сделано вручную, перебирая последовательности:

public override List<Item> SearchListWithSearchPhrase(string searchPhrase) 
{ 
    List<string> searchTerms = StringHelpers.GetSearchTerms(searchPhrase); 

    using (var db = Datasource.GetContext()) 
    { 
     IQueryable<Task> taskQuery = db.Tasks.AsQueryable(); 
     foreach(var term in searchTerms) 
     { 
       taskQuery = taskQuery.Where(t=>t.Title.ToUpper().Contains(term.ToUpper()) && t.Description.ToUpper().Contains(term.ToUpper()))    
     } 
     return taskQuery.ToList(); 
    } 
} 

ум, что запрос все еще выполняется СУБД, как SQL заявление. Единственный недостаток заключается в том, что список searchTerms не должен быть длинным - иначе созданный SQL-оператор не будет эффективным.

+0

это выглядит хорошо, но я не могу заставить его работать, я продолжаю получать: текст типа данных аргумента недействителен для аргумента 1 верхней функции. –

+0

Если в столбцах базы данных Title и Description есть тип TEXT, тогда большинство операторов, таких как CONTAINS ('like') и, возможно, TOUPPER не будут работать. Столбцы TEXT должны быть запрошены с помощью индекса полного поиска текста и хранимых процедур, а не linq. Поэтому либо используйте FTS (http: // msdn.microsoft.com/en-us/library/ms142571.aspx) или изменить столбцы с TEXT на NVARCHAR (MAX). (Я говорю о SQL-сервере) – PanJanek

Смежные вопросы