按多个字段搜索

时间:2015-03-11 19:35:46

标签: c# asp.net-mvc linq

我正在研究一个项目,并使用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语句。

有没有更好的方法来处理多个字段的搜索?

2 个答案:

答案 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;
    }
}