【问题标题】:Why does this LINQ-to-SQL query get a NotSupportedException?为什么此 LINQ-to-SQL 查询会得到 NotSupportedException?
【发布时间】:2009-12-08 13:02:45
【问题描述】:

以下 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:本地 序列不能在 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;
        }
    }
}

【问题讨论】:

  • 请注意,这不是“未实现”错误,而是“无法使用本地序列”错误。
  • 我不确定我是否正确阅读了这篇文章,它有很多括号,但我没有看到格式良好的 where 子句。您的 searchTerms.All() 正在返回一个不构成 where 子句的字符串列表,因此会出现错误。
  • searchTerms.All() 只是遍历字符串集合但返回一个 List,这里有一个类似的例子:stackoverflow.com/questions/1866018/…

标签: c# linq linq-to-sql


【解决方案1】:

Ed,我遇到了类似的情况。代码如下。重要的代码行是我设置 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;

【讨论】:

    【解决方案2】:

    由于您无法将本地序列与 linq 表连接,将上述查询转换为 SQL 的唯一方法是创建 WHERE 子句,其中包含与 searchTerms 列表中的元素一样多的 LIKE 条件(与 AND 运算符连接)。显然 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();
        }
    }
    

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

    【讨论】:

    • 这看起来不错,但我无法让它工作,我不断收到:Argument data type text is invalid for argument 1 of upper function。
    • 如果您的数据库列 Title 和 Description 具有 TEXT 类型,那么大多数运算符,如 CONTAINS ('like'),并且可能 TOUPPER 将不起作用。 TEXT 列应通过全文搜索索引和存储过程而不是 linq 进行查询。因此,要么使用 FTS (msdn.microsoft.com/en-us/library/ms142571.aspx),要么将列从 TEXT 更改为 NVARCHAR(MAX)。 (我说的是 SQL 服务器)
    猜你喜欢
    • 1970-01-01
    • 2019-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-11
    相关资源
    最近更新 更多