C# - 如何在对象列表上执行多个包含过滤器
C# - How to do multiple contains filters on an object list
我有一个数据 table,我正在尝试对列实施服务器端过滤。我允许每个列查询多个字符串,并试图确定逐步通过所有过滤器的最佳方式。下面是 table 对象的示例,为了简单起见,只有 2 个参数。
//table models from db
public class Parts
{
public string PartName { get; set; }
public virtual Series Series { get; set; }
}
public class Series
{
public string SeriesName { get; set; }
}
//This is what is passed in from the datatable filter query
public class PartsTable
{
public string PartName { get; set; }
public string SeriesName { get; set; }
}
public IEnumerable<Parts> PartsTableSearch(PartsTable table)
{
//Queries come in as comma separated string
var partNameList = table.PartName?.Split(',');
var seriesNameList = table.SeriesName?.Split(',');
//Gets and generates the list of Parts
var fullList = GetParts();
if (partNameList != null && partNameList.Length > 0)
{
foreach (var partName in partNameList)
{
fullList = fullList.Where(p => p.PartName.ToLower().Contains(name.ToLower()));
}
}
if (seriesNameList != null && seriesNameList.Length > 0)
{
foreach (var seriesName in seriesNameList)
{
fullList = fullList.Where(p => p.Series.SeriesName.ToLower().Contains(seriesName.ToLower()));
}
}
return fullList;
}
这对我想要的不起作用,因为对于每个参数(即 PartName),我需要能够 return 所有具有包含 partNameList 中的搜索字符串的 PartName 的对象,然后根据该结果,进一步过滤包含 seriesNameList 中搜索字符串的 SeriesName,然后 return 结果集。但是,partNameList 的查询可能是空白的,只能搜索 seriesName,反之亦然。有什么建议么?我觉得这是一个明显的答案,我只是忽略了,尽管我搜索过的任何其他内容都只适用于单个查询过滤器。提前致谢。
这可以通过两种方式使用单个 .Where
来完成:
使用 .Contain()
将 return 完全匹配:
public IEnumerable<Parts> PartsTableSearch(PartsTable table)
{
//Queries come in as comma separated string
var partNameList = table.PartName?.Split(',');
var seriesNameList = table.SeriesName?.Split(',');
//Gets and generates the list of Parts
var fullList = GetParts()
.Where(p => partNameList.Contains(p.PartName.ToLower())
|| seriesNameList.Contains(p.Series.SeriesName.ToLower()))
.ToList();
return fullList;
}
使用 .Any()
将 return 部分匹配:
public IEnumerable<Parts> PartsTableSearch(PartsTable table)
{
//Queries come in as comma separated string
var partNameList = table.PartName?.Split(',');
var seriesNameList = table.SeriesName?.Split(',');
//Gets and generates the list of Parts
var fullList = GetParts()
.Where(p => partNameList.Any(n => n.Contains(p.PartName.ToLower())))
|| seriesNameList.Any(n => n.Contains(p.Series.SeriesName.ToLower())))
.ToList();
return fullList;
}
这是为 LinqToSql 制作的。有人告诉我它不适用于 Entity Framework。它应该与内存中的集合一起使用。
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;
}
这样调用:
public IEnumerable<Parts> PartsTableSearch(PartsTable table)
{
var fullList = GetParts();
var filters = new List<Expression<Func<Part, bool>>>();
if (table.PartName != null)
{
var partNameList = table.PartName.ToLower().Split(',');
foreach (var partName in partNameList)
{
filters.Add(p => p.PartName.ToLower().Contains(partName));
}
}
if (table.SeriesName != null)
{
var seriesNameList = table.SeriesName.ToLower().Split(',');
foreach (var seriesName in seriesNameList)
{
filters.Add(p => p.Series.SeriesName.ToLower().Contains(seriesName));
}
}
Expression<Func<Part, bool>> filter = filters.OrTheseFiltersTogether();
return fullList.Where(filter);
}
对从不同查询获得的每个结果集使用 Yield return
。如果它为 null 并不重要,所有结果都将收集在 IEnumerable<Parts>
中。
public IEnumerable<Parts> PartsTableSearch(PartsTable table)
{
//Queries come in as comma separated string
var partNameList = table.PartName?.Split(',');
var seriesNameList = table.SeriesName?.Split(',');
//Gets and generates the list of Parts
var fullList = GetParts();
if (partNameList != null && partNameList.Length > 0)
{
foreach (var partName in partNameList)
{
yield return fullList.Where(p => p.PartName.ToLower().Contains(name.ToLower()));
}
}
if (seriesNameList != null && seriesNameList.Length > 0)
{
foreach (var seriesName in seriesNameList)
{
yield return fullList.Where(p => p.Series.SeriesName.ToLower().Contains(seriesName.ToLower()));
}
}
yield return null;
}
这就是我最终让它工作的方式。
var fullList = GetParts();
if (partNameList != null && partNameList.Length > 0)
{
var tempList = new List<Parts>();
foreach (var partName in partNameList)
{
tempList.AddRange(fullList.Where(p => p.PartName.ToLower().Contains(partName.ToLower().Trim())));
}
fullList = tempList;
}
if (seriesNameList != null && seriesNameList.Length > 0)
{
var tempList = new List<Parts>();
foreach (var seriesName in seriesNameList)
{
tempList.AddRange(fullList.Where(p => p.Series.SeriesName.ToLower().Contains(seriesName.ToLower().Trim())).ToList());
}
fullList = tempList;
}
return fullList.ToList();
我有一个数据 table,我正在尝试对列实施服务器端过滤。我允许每个列查询多个字符串,并试图确定逐步通过所有过滤器的最佳方式。下面是 table 对象的示例,为了简单起见,只有 2 个参数。
//table models from db
public class Parts
{
public string PartName { get; set; }
public virtual Series Series { get; set; }
}
public class Series
{
public string SeriesName { get; set; }
}
//This is what is passed in from the datatable filter query
public class PartsTable
{
public string PartName { get; set; }
public string SeriesName { get; set; }
}
public IEnumerable<Parts> PartsTableSearch(PartsTable table)
{
//Queries come in as comma separated string
var partNameList = table.PartName?.Split(',');
var seriesNameList = table.SeriesName?.Split(',');
//Gets and generates the list of Parts
var fullList = GetParts();
if (partNameList != null && partNameList.Length > 0)
{
foreach (var partName in partNameList)
{
fullList = fullList.Where(p => p.PartName.ToLower().Contains(name.ToLower()));
}
}
if (seriesNameList != null && seriesNameList.Length > 0)
{
foreach (var seriesName in seriesNameList)
{
fullList = fullList.Where(p => p.Series.SeriesName.ToLower().Contains(seriesName.ToLower()));
}
}
return fullList;
}
这对我想要的不起作用,因为对于每个参数(即 PartName),我需要能够 return 所有具有包含 partNameList 中的搜索字符串的 PartName 的对象,然后根据该结果,进一步过滤包含 seriesNameList 中搜索字符串的 SeriesName,然后 return 结果集。但是,partNameList 的查询可能是空白的,只能搜索 seriesName,反之亦然。有什么建议么?我觉得这是一个明显的答案,我只是忽略了,尽管我搜索过的任何其他内容都只适用于单个查询过滤器。提前致谢。
这可以通过两种方式使用单个 .Where
来完成:
使用 .Contain()
将 return 完全匹配:
public IEnumerable<Parts> PartsTableSearch(PartsTable table)
{
//Queries come in as comma separated string
var partNameList = table.PartName?.Split(',');
var seriesNameList = table.SeriesName?.Split(',');
//Gets and generates the list of Parts
var fullList = GetParts()
.Where(p => partNameList.Contains(p.PartName.ToLower())
|| seriesNameList.Contains(p.Series.SeriesName.ToLower()))
.ToList();
return fullList;
}
使用 .Any()
将 return 部分匹配:
public IEnumerable<Parts> PartsTableSearch(PartsTable table)
{
//Queries come in as comma separated string
var partNameList = table.PartName?.Split(',');
var seriesNameList = table.SeriesName?.Split(',');
//Gets and generates the list of Parts
var fullList = GetParts()
.Where(p => partNameList.Any(n => n.Contains(p.PartName.ToLower())))
|| seriesNameList.Any(n => n.Contains(p.Series.SeriesName.ToLower())))
.ToList();
return fullList;
}
这是为 LinqToSql 制作的。有人告诉我它不适用于 Entity Framework。它应该与内存中的集合一起使用。
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;
}
这样调用:
public IEnumerable<Parts> PartsTableSearch(PartsTable table)
{
var fullList = GetParts();
var filters = new List<Expression<Func<Part, bool>>>();
if (table.PartName != null)
{
var partNameList = table.PartName.ToLower().Split(',');
foreach (var partName in partNameList)
{
filters.Add(p => p.PartName.ToLower().Contains(partName));
}
}
if (table.SeriesName != null)
{
var seriesNameList = table.SeriesName.ToLower().Split(',');
foreach (var seriesName in seriesNameList)
{
filters.Add(p => p.Series.SeriesName.ToLower().Contains(seriesName));
}
}
Expression<Func<Part, bool>> filter = filters.OrTheseFiltersTogether();
return fullList.Where(filter);
}
对从不同查询获得的每个结果集使用 Yield return
。如果它为 null 并不重要,所有结果都将收集在 IEnumerable<Parts>
中。
public IEnumerable<Parts> PartsTableSearch(PartsTable table)
{
//Queries come in as comma separated string
var partNameList = table.PartName?.Split(',');
var seriesNameList = table.SeriesName?.Split(',');
//Gets and generates the list of Parts
var fullList = GetParts();
if (partNameList != null && partNameList.Length > 0)
{
foreach (var partName in partNameList)
{
yield return fullList.Where(p => p.PartName.ToLower().Contains(name.ToLower()));
}
}
if (seriesNameList != null && seriesNameList.Length > 0)
{
foreach (var seriesName in seriesNameList)
{
yield return fullList.Where(p => p.Series.SeriesName.ToLower().Contains(seriesName.ToLower()));
}
}
yield return null;
}
这就是我最终让它工作的方式。
var fullList = GetParts();
if (partNameList != null && partNameList.Length > 0)
{
var tempList = new List<Parts>();
foreach (var partName in partNameList)
{
tempList.AddRange(fullList.Where(p => p.PartName.ToLower().Contains(partName.ToLower().Trim())));
}
fullList = tempList;
}
if (seriesNameList != null && seriesNameList.Length > 0)
{
var tempList = new List<Parts>();
foreach (var seriesName in seriesNameList)
{
tempList.AddRange(fullList.Where(p => p.Series.SeriesName.ToLower().Contains(seriesName.ToLower().Trim())).ToList());
}
fullList = tempList;
}
return fullList.ToList();