本地序列不能在 LINQ to SQL 实现中使用
当我尝试生成 MappedItem 类的列表时,出现错误,请参见下文。简而言之,下面的代码示例尝试按类别、日期范围和 SKU 查找产品。我的要求是,用户应该能够输入以逗号分隔的 SKU 列表,并且搜索是查找 SKU 以用户输入的 SKU 之一开头的任何产品。当我运行代码时,我明白了。
本地序列不能在查询运算符的 LINQ to SQL 实现中使用(Contains() 运算符除外)。
缩写顺序是这样的:
将逗号分隔的 SKU 字符串转换为字符串列表。
string sku = TextSKU.Text;
List<string> skuList = sku.Split(new char[] { ',' }).ToList();
在代码的其他位置定义将接受搜索结果的类。
public class MappedItem
{
public string ItemDescription { get; set; }
public int ItemCount { get; set; }
public MappedItem()
{
}
public MappedItem(string itemDescription, int itemCount)
{
ItemDescription = itemDescription;
ItemCount = itemCount;
}
}
这是我生成结果的查询,
List<MappedItem> widgetItems = (from c1 in db.CCRCodes
join pac in db.widgetAssignedCodes on c1.code_id equals pac.code_id
join ph in db.widgetHistories on pac.history_id equals ph.history_id
where ph.contact_dt.Value.Date >= startDate && ph.contact_dt.Value.Date <= endDate &&
(string.IsNullOrEmpty(baanCatFam) || ph.baan_cat_family_code == baanCatFam) &&
(string.IsNullOrEmpty(baanCat) || ph.baan_cat_code == baanCat) &&
(string.IsNullOrEmpty(baanSubCat) || (ph.baan_sub_cat_code == baanSubCat)) &&
(string.IsNullOrEmpty(sku) || skuList.All(sl => ph.product_mod.StartsWith(sl)))
group c1 by c1.code_desc into ct
select new MappedItem
{
ItemDescription = ct.Key.ToUpper(),
ItemCount = ct.Count()
}).OrderByDescending(m => m.ItemCount)
.ToList();
我相信罪魁祸首是我在下面提取并显示的代码行。
skuList.All(sl => ph.product_mod.StartsWith(sl))
这标识了以 skuList 中的元素开头的所有 sku,skuList 是从用户输入的逗号分隔的 sku 列表派生的。我的问题是,是什么导致了这个错误,并给出了代码示例,我该如何解决它们。
I'm getting an error, see below, when I try to generate a list of the class MappedItem. In short the code example below tries to find products by category, date range and SKU. The requirement I have is that the user should be able to enter a comma separated list of SKUs and the search is to find any product whos SKU starts with one of the SKUs entered by the user. When I run the code, I get.
Local sequence cannot be used in LINQ to SQL implementation of query operators except the Contains() operator.
The abbreviated sequence is this:
Convert the comma separated string of SKUs into a list of strings.
string sku = TextSKU.Text;
List<string> skuList = sku.Split(new char[] { ',' }).ToList();
Define elsewhere in the code the class that will accept the search results.
public class MappedItem
{
public string ItemDescription { get; set; }
public int ItemCount { get; set; }
public MappedItem()
{
}
public MappedItem(string itemDescription, int itemCount)
{
ItemDescription = itemDescription;
ItemCount = itemCount;
}
}
Here's the query that I generate my results from
List<MappedItem> widgetItems = (from c1 in db.CCRCodes
join pac in db.widgetAssignedCodes on c1.code_id equals pac.code_id
join ph in db.widgetHistories on pac.history_id equals ph.history_id
where ph.contact_dt.Value.Date >= startDate && ph.contact_dt.Value.Date <= endDate &&
(string.IsNullOrEmpty(baanCatFam) || ph.baan_cat_family_code == baanCatFam) &&
(string.IsNullOrEmpty(baanCat) || ph.baan_cat_code == baanCat) &&
(string.IsNullOrEmpty(baanSubCat) || (ph.baan_sub_cat_code == baanSubCat)) &&
(string.IsNullOrEmpty(sku) || skuList.All(sl => ph.product_mod.StartsWith(sl)))
group c1 by c1.code_desc into ct
select new MappedItem
{
ItemDescription = ct.Key.ToUpper(),
ItemCount = ct.Count()
}).OrderByDescending(m => m.ItemCount)
.ToList();
I believe that the culprit is the line of code that I've extracted and displayed below.
skuList.All(sl => ph.product_mod.StartsWith(sl))
This identifies all skus that start with an element from the skuList which is derived from a comma delimited lists of skus entered by the user. My question is, what causes this error, and given the code examples, what do I do to get around them.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
首先 - 从逻辑上讲你想要任何,而不是全部。
其次,这是建立查询过滤器的糟糕方法。所有这些操作都被发送到数据库中,而确定应应用哪些过滤器的信息已经是本地的。显式连接也很糟糕(可以使用关联属性来代替)。
第三:回答你的问题。
LinqToSql 的查询提供程序无法将您的本地集合转换为 sql。它只能在有限的场景中进行转换...
.Where(ph => idList.Contains(ph.Id))
被转换为 IN 子句,idList 中的每个 int 有 1 个参数。要解决此限制,您需要将本地集合转换为表达式。首先将集合中的每个项目转换为过滤表达式:
接下来是一个辅助方法:
现在将它们放在一起:
First - logically you want Any, not All.
Second, this is a poor way to build up a query filter. All of those operations are sent into the database, while the information to determine which filters should be applied is already local. The explicit joins are also bad (association properties could be used instead).
Third: the answer to your question.
LinqToSql's query provider cannot translate your local collection into sql. There's only a limitted set of scenarios where it can translate...
.Where(ph => idList.Contains(ph.Id))
is translated into an IN clause with 1 parameter per int in idList.To get around this limitation, you need to convert the local collection into an expression. Start by tranforming each item in the collection into a filtering expression:
Next, a helper method:
And now putting it all together: