我正在研究一个项目,并使用LINQ在MVC中实现了多个字段的搜索,如下所示:
public ActionResult SearchResult(SearchViewModel model)
{
List<Requisition> emptyList = new List<Requisition>();
if (model.RequisitionID > 0
|| model.Department > 0
|| model.Status > 0
|| model.RequisitionedBy != null)
{
var results = db.Requisitions.Where(x => x.RequisitionId > 0);
results = ProcessSearchInput(model, results);
return PartialView(results.ToList());
}
return PartialView(emptyList);
}
助手:
private static IQueryable<Requisition> ProcessSearchInput(SearchViewModel model, IQueryable<Requisition> results)
{
if (model.Department > 0)
results = results.Where(x => x.Department == model.Department);
if (model.RequisitionedBy != null)
results = results.Where(x => x.Requisitioned_By.Contains(model.RequisitionedBy));
if (model.Status > 0)
results = results.Where(x => x.Status.Contains(model.Status.ToString()));
return results;
}
此代码工作正常。 但是,如果我在表单中添加一个额外的搜索字段,我还需要在控制器中添加一个单独的if语句。 使用当前方法,ProcessSearchInput方法将包含太多if语句。
有没有更好的方法来处理多个字段的搜索?
答案 0 :(得分:1)
您当前的做法违反了开放式封闭原则。解决方案是创建一个动态过滤器,如this示例。然而,这是一个复杂的解决方案,只有当您要在此过程中添加越来越多的过滤器时才值得。如果没有,那就不要打扰。
答案 1 :(得分:0)
我同意之前的评论:您当前的解决方案可能是要走的路。 在现实世界中,您很快就必须实施过滤器,例如所有在纽约拥有结算地址或送货地址的客户,以及更复杂的内容。到那时,所有聪明的通用东西都会挡路。
但是,如果您保证永远不会在生产代码中使用它: 您可以通过示例使用查询来节省大量的输入,其中您将过滤器指定为源包含的类型的实例:
var example = new Requisition { Department = 8, Requisitioned_By ="john" };
var result = db.Requisitions.FilterByExample(example);
这是一个简单的实现:
public static class FilterByExampleHelper
{
public static IQueryable<T> FilterByExample<T>(this IQueryable<T> source, T example) where T : class
{
foreach (var property in typeof(T).GetProperties(BindingFlags.Public|BindingFlags.Instance).Where(p => p.CanRead))
{
ConstantExpression valueEx = null;
var propertyType = property.PropertyType;
if (propertyType.IsValueType)
{
var value = property.GetValue(example);
if (value != null &&
!value.Equals(Activator.CreateInstance(propertyType)))
{
valueEx = Expression.Constant(value, propertyType);
}
}
if (propertyType == typeof(string))
{
var value = property.GetValue(example) as string;
if (!string.IsNullOrEmpty(value))
{
valueEx = Expression.Constant(value);
}
}
if (valueEx == null)
{
continue;
}
var parameterEx = Expression.Parameter(typeof(T));
var propertyEx = Expression.Property(parameterEx, property);
var equalsEx = Expression.Equal(propertyEx, valueEx);
var lambdaEx = Expression.Lambda(equalsEx, parameterEx) as Expression<Func<T, bool>>;
source = source.Where(lambdaEx);
}
return source;
}
}