有条件地调用Linq扩展方法

时间:2016-12-23 12:23:07

标签: c# entity-framework linq

我有一个抽象类来实现我的所有查询。我的Get功能是:

public virtual List<TEntity> Get(Expression<Func<TEntity, bool>> criteria)
{
    return _dbSet.Where(criteria).OrderByDescending(OrderBy).ThenBy(ThenOrderBy).ToList();
}

ThenOrderBy属性为:

public virtual Func<TEntity, object> ThenOrderBy { get; set; }

OrderBy 属性是必需的,但我的新属性 ThenOrderBy 不是必需的,并且未在继承此抽象类的所有类中实现。

我收到此错误:

  

值不能为空

有没有办法保留这些干净的代码而不会放置“if's”的句子?

我使用的解决方案:

public virtual List<TEntity> Consultar(Expression<Func<TEntity, bool>> criteria)
{
    var query = _dbSet.Where(criteria);
    query = OrderDescending ?
            query.OrderByDescending(OrderBy).AndOptionallyBy(ThenOrderBy) 
            : 
            query.OrderBy(OrderBy).AndOptionallyBy(ThenOrderBy);
    query = (paggedSearch && Skip > 0) ? query.Skip(Skip) : query;
    query = (paggedSearch && Take > 0) ? query.Take(Take) : query;

    return query.ToList();
}

并创建了一个新的扩展类

public static class ExtensionMethods
{
    public static IOrderedQueryable<TSource> AndOptionallyBy<TSource, TKey>(this IOrderedQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector)
    {
        return (keySelector == null) ? source : source.ThenBy(keySelector);
    }
}

5 个答案:

答案 0 :(得分:5)

不,你需要用if阻止它。但是,您可以在不访问数据库的情况下构建EF查询:

public virtual List<TEntity> Get(Expression<Func<TEntity, bool>> criteria)
{
    var query = _dbSet.Where(criteria);

    if(OrderBy != null)
    {
        query = query.OrderByDescending(OrderBy);

        if(ThenOrderBy != null)
        {
            query = query.ThenBy(ThenOrderBy);
        }
    }

    return query.ToList();
}

答案 1 :(得分:4)

如果短暂则:

public virtual List<TEntity> Get(Expression<Func<TEntity, bool>> criteria)
{ 
     var result = _dbSet.Where(criteria).OrderByDescending(OrderBy);
     if(ThenOrderBy != null)
     {
        result = result.ThenBy(ThenOrderBy);
     }
     return result.ToList();
}

答案 2 :(得分:3)

有时最干净的解决方案 使用一堆print_name语句。在这种情况下,您可以检查if()是否为空:

ThenOrderBy

当然,有很多方法可以滥用语法来压缩这段代码,但明确发生的事情会使代码更易于阅读,因此更加清晰。

答案 3 :(得分:3)

您可以创建自己的AndOptionallyBy方法,如果提供了第二个条件,或者保留IOrderedQueryable,例如:

public static IOrderedQueryable<TSource> AndOptionallyBy<TSource, TKey>(
    this IOrderedQueryable<TSource> source,
    Expression<Func<TSource, TKey>> keySelector)
{
    if (keySelector==null)
    {
        return source;
    }
    else
    {
        return source.ThenBy(keySelector);
    }
}

我不会用这个。虽然这允许您使用函数链,但它会让代码的维护者感到惊讶。

一方面你有:

var result = _dbSet.Where(criteria)
                   .OrderByDescending(OrderBy)
                   .AndOptionallyBy(ThenOrderBy)
                   .ToList();

另一方

var query = _dbSet.Where(criteria)
                  .OrderByDescending(OrderBy);
if (ThenOrderBy!=null)
{
    query = query.ThenBy(ThenOrderBy);
}
var result = query.ToList();

您认为哪个人对其他人更清楚?

<强>更新

使用条件创建分页查询很容易:

var query = _dbSet.Where(criteria);
var orderedQuery=OrderDescending 
                       ?query.OrderByDescending(OrderBy)
                       :query.OrderBy(OrderBy);
if (buscaPaginada)
{
    if (Skip > 0)
    {
        query = query.Skip(Skip);
    }
    if (Take >0)
    {
        query = query.Skip(Skip);
    }
}
return query.ToList();

答案 4 :(得分:1)

如果您希望ThenBy具有默认行为,则只需将其默认为不会影响排序的内容而不是null。例如entity => 1

我测试了它,如下所示,这使我无法设置OrderByThenOrderBy,它仍然按预期工作:

public class TestClass<TEntity>
{
    private IEnumerable<TEntity> data;

    public TestClass(IEnumerable<TEntity> data){
        OrderBy = (t) => 1;
        ThenOrderBy = (t) => 1;
        this.data = data;
    }

    public IEnumerable<TEntity> Get(Func<TEntity, bool> criteria){
        return data.Where(criteria).OrderBy(OrderBy).ThenBy(ThenOrderBy);
    }
    public Func<TEntity, object> OrderBy { get; set; }
    public Func<TEntity, object> ThenOrderBy { get; set; }
}

实例(您可以取消注释ThenOrderBy行以查看是否使用):http://rextester.com/YFOB38755

顺便说一句,您的现有代码可以更多更易读/更简单:

public virtual List<TEntity> Get(Expression<Func<TEntity, bool>> criteria)
{
    IEnumerable<TEntity> query = _dbSet.Where(criteria);
    query = OrderDescending ? query.OrderByDescending(OrderBy) : query.OrderBy(OrderBy)
    if (paggedSearch)
    {            
        if(Skip > 0)
            query = query.Skip(Skip);
        if(Take > 0)
            query = query.Take(Take);
    }    
    return query.ToList();
}

没有必要继续重复(干!)