linq-to-sql - 本地序列不能在 LINQ to SQL 实现中使用

标签 linq-to-sql contains startswith

当我尝试生成类 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 中的元素开头的所有 skus,该元素源自用户输入的以逗号分隔的 skus 列表。我的问题是,是什么导致了这个错误,并给出了代码示例,我该怎么做才能解决它们。

最佳答案

首先 - 逻辑上你想要任何,而不是全部。

其次,这是一种构建查询过滤器的糟糕方法。所有这些操作都被发送到数据库中,而确定应该应用哪些过滤器的信息已经是本地的。显式连接也不好(可以使用关联属性代替)。

IQueryable<WidgetHistory> query =  db.widgetHistories
  .Where(ph => ph.contact_dt.Value.Date >= startDate
    && ph.contact_dt.Value.Date <= endDate);

if (!string.IsNullOrEmpty(baanCatFam))
{
  query = query.Where(ph => ph.baan_cat_family_code == baanCatFam);
}
if (!string.IsNullOrEmpty(baanCat))
{
  query = query.Where(ph => ph.baan_cat_code == baanCat);
}
if (!string.IsNullOrEmpty(baanSubCat))
{
  query = query.Where(ph => ph.baan_sub_cat_code == baanSubCat);
}

//TODO sku filtering here.

List<MappedItem> widgetItems =
  from ph in query
  let c1 = ph.widgetAssignedCode.CCRCode
  group c1 by c1.code_desc into g
  select new MappedItem
  {
    ItemDescription = g.Key.ToUpper(),
    ItemCount = g.Count()
  }).OrderByDescending(m => m.ItemCount)
  .ToList();

第三:回答你的问题。

what causes this error



LinqToSql 的查询提供程序无法将您的本地集合转换为 sql。它可以翻译的场景有限... .Where(ph => idList.Contains(ph.Id))被翻译成一个 IN 子句,在 idList 中每个 int 有 1 个参数。

要解决此限制,您需要将本地集合转换为表达式。首先将集合中的每个项目转换为过滤表达式:
List<Expression<Func<WidgetHistory, bool>>> skuFilters =
  skuList.Select<string, Expression<Func<WidgetHistory, bool>>>(skuItem =>
    ph => ph.ProductMod.StartsWith(skuItem)
  ).ToList();

接下来是一个辅助方法:
public static Expression<Func<T, bool>> OrTheseFiltersTogether<T>(
  this IEnumerable<Expression<Func<T, bool>>> filters)
{
  Expression<Func<T, bool>> firstFilter = filters.FirstOrDefault();
  if (firstFilter == null)
  {
    Expression<Func<T, bool>> alwaysTrue = x => true;
    return alwaysTrue;
  }
  var body = firstFilter.Body;
  var param = firstFilter.Parameters.ToArray();
  foreach (var nextFilter in filters.Skip(1))
  {
    var nextBody = Expression.Invoke(nextFilter, param);
    body = Expression.OrElse(body, nextBody);
  }
  Expression<Func<T, bool>> result = Expression.Lambda<Func<T, bool>>(body, param);
  return result;
}

现在把它们放在一起:
if (skuFilters.Any())  //this part goes into where it says "TODO"
{
  Expression<Func<WidgetHistory, bool>> theSkuFilter = skuFilters.OrTheseFiltersTogether()
  query = query.Where(theSkuFilter);
}

关于linq-to-sql - 本地序列不能在 LINQ to SQL 实现中使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5008839/

相关文章:

c# - SQLite:设计数据库并使用自动增量 ID 访问其数据的正确方法?

string - 如何在powershell中检查字符串是否包含数字

java - 为什么 Java 中的 contains() 方法不能按预期工作?

lucene - 如何使用Lucene.NET 3.0进行startsWith然后Contains搜索?

linq - 为什么空集的总和为空?

c# - 在存储过程中使用 LIKE 命令

C# 不四舍五入

java - 所有出现的包含方法

c# - 字符串以顺序开头

python - Pandas 数据框中以相同字符串开头的列的总和值