为什么这个LINQ-to-SQL查询会出现NotSupportedException?

时间:2009-12-08 13:02:45

标签: c# linq linq-to-sql

以下 LINQ 声明:

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:Local   序列不能在LINQ to SQL中使用   查询运算符的实现   除了Contains()运算符。

环顾四周似乎我唯一的选择就是将所有我的项第一个纳入一个通用列表,然后对其进行LINQ查询。

或者是否有一种巧妙的方法来重新编写上述LINQ-to-SQL语句以避免错误?

解答:

感谢Randy,您的想法帮助我构建了以下解决方案。它不优雅,但它解决了问题,因为这将是代码生成,我可以处理例如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;
        }
    }
}

2 个答案:

答案 0 :(得分: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;

答案 1 :(得分:1)

由于您无法使用linq表连接本地序列,因此将上述查询转换为SQL的唯一方法是创建具有与searchTerms列表中的元素一样多的LIKE条件的WHERE子句(与AND运算符连接)。显然linq不会自动执行此操作而是抛出一个expception。 但它可以通过迭代序列手动完成:

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();
    }
}

请注意,DBMS仍然将查询作为SQL语句执行。唯一的缺点是searchTerms列表不应该很长 - 否则生成的SQL语句不会有效。