Linq to sql 本地序列不能用于LINQ到SQL的实现

Linq to sql 本地序列不能用于LINQ到SQL的实现,linq-to-sql,contains,startswith,Linq To Sql,Contains,Startswith,当我试图生成类MappeItem的列表时,出现了一个错误,请参见下面的。简而言之,下面的代码示例尝试按类别、日期范围和SKU查找产品。我的要求是,用户应该能够输入一个逗号分隔的SKU列表,搜索是查找任何SKU以用户输入的SKU之一开头的产品。当我运行代码时,我得到了 除了Contains()运算符外,查询运算符的LINQ to SQL实现中不能使用局部序列 缩写顺序如下: 将以逗号分隔的SKU字符串转换为字符串列表 string sku = TextSKU.Text; List<strin

当我试图生成类MappeItem的列表时,出现了一个错误,请参见下面的。简而言之,下面的代码示例尝试按类别、日期范围和SKU查找产品。我的要求是,用户应该能够输入一个逗号分隔的SKU列表,搜索是查找任何SKU以用户输入的SKU之一开头的产品。当我运行代码时,我得到了

除了Contains()运算符外,查询运算符的LINQ to SQL实现中不能使用局部序列

缩写顺序如下:

将以逗号分隔的SKU字符串转换为字符串列表

string sku = TextSKU.Text;
List<string> skuList = sku.Split(new char[] { ',' }).ToList();
这是我生成结果的查询

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中的元素开头的所有SKU,skuList源自用户输入的以逗号分隔的SKU列表。我的问题是,是什么导致了这个错误,并且给出了代码示例,我该怎么做才能避免这些错误。

首先-从逻辑上讲,您想要任何错误,而不是所有错误

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

接下来,一个助手方法:

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;
}
公共静态表达式或过滤器组合在一起(
这是(可数过滤器)
{
表达式firstFilter=filters.FirstOrDefault();
if(firstFilter==null)
{
表达式alwaysTrue=x=>true;
始终返回;
}
var body=firstFilter.body;
var param=firstFilter.Parameters.ToArray();
foreach(过滤器中的var nextFilter.Skip(1))
{
var nextBody=Expression.Invoke(nextFilter,param);
body=Expression.OrElse(body,nextBody);
}
表达式结果=表达式.Lambda(body,param);
返回结果;
}
现在把所有这些放在一起:

if (skuFilters.Any())  //this part goes into where it says "TODO"
{
  Expression<Func<WidgetHistory, bool>> theSkuFilter = skuFilters.OrTheseFiltersTogether()
  query = query.Where(theSkuFilter);
}
if(skuFilters.Any())//此部分进入显示“TODO”的位置
{
表达式Theskuffilter=skuffilters.OrTheseFiltersTogether()
query=query.Where(塞斯克过滤器);
}
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();
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);
}