如何将Linq存放在物业的条件中

时间:2011-03-16 10:27:32

标签: linq entity-framework expression-trees

我想知道在参数中存储实体条件的最可维护方式(如果存在),以便在条件中的每个linq中重用它。

假设有一个产品实体:

public class Product
{
    public bool IsDiscontinued { get; set; }

    public int UnitsInStock { get; set; }
}

我想在Product类中添加一个属性IsOnSale,其中包含确定产品是否在售的逻辑。 在这个简单的例子中,逻辑可以是:

IsOnSale = IsDiscontinued == false && UnitsInStock > 0

然后我应该能够编写这种类型的linq查询:

from p in context.Products
where p.IsOnSale == true
select p

解决方案的目的应该是,如果将来确定产品是否在销售中的逻辑发生变化(例如添加属性IsBackOrderAllowed),我不必在任何地方编辑linq查询,而只是简单必须改变IsOnSale属性。

类似的问题已发布here,但似乎解决了一个更具体的问题。

4 个答案:

答案 0 :(得分:2)

您可以这样做:

Func<Product, bool> isOnSaleFunc = 
                          (p => p.IsDiscontinued == false && p.UnitsInStock > 0);

然后在您的查询中执行:

context.Products.Where(isOnSaleFunc)

<强>更新

作为与@DoctaJonez的评论讨论的结果 - 使用这种方法的过滤将在客户端执行(这或者当然效率低下),因此应该使用Expression<Func<Product, bool>>而不是{{} 1}}。

答案 1 :(得分:1)

您可以创建一个方法,返回根据您的条件筛选的IQueryable:

public IQueryable<Product> WhereOnSale(this IQueryable<Product> source)
{
    return source.Where(p => p.IsDiscontinued == false && p.UnitsInStock > 0);
}

你会像这样使用它:

from p in context.Products.WhereOnSale()
select p

如果您想使用Yakimych的答案中的表达方式,那么这将有效:

Expression<Func<Product, bool>> isOnSale = 
(p => p.IsDiscontinued == false && p.UnitsInStock > 0);

你可以像这样使用它:

context.Products.Where(isOnSale)

将它声明为表达式非常重要,否则实体框架将无法将其转换为SQL,因为lambda将被编译为IL而不是表达式树。

答案 2 :(得分:1)

这里的第一个问题是linq to entities不能使用不属于模型的属性(=它不能用于自定义属性)。

您必须定义表达式。如果仅定义Func,它将作为Linq执行到对象:

public class Product
{
    ...

    public static Expression<Func<Product, bool>> IsOnSale
    {
        get
        {
            return p => (p.IsDiscontinued == false && p.UnitsInStock > 0);
        }
    }
}

现在您必须以这种方式调用查询:

var query = context.Products.Where(Product.IsOnSale);

另一种方法是使用model defined function

答案 3 :(得分:0)

我认为您正在寻找规范模式。

http://huyrua.wordpress.com/2010/07/13/entity-framework-4-poco-repository-and-specification-pattern/提供了一篇关于在EF中使用它的文章,其中包含一个基本实现。

如何实现这一点的一个例子是进行查询

from p in context.Products
where ProductSpecifications.IsOnSale.Predicate
select p

并使用以下帮助程序和规范定义。

public static class ProductSpecifications{
     public static readonly Specification<Product> IsOnSale = new Specification<Product>(x => !x.IsDiscontinued && x.UnitsInStock > 0);  
}

public class Specification<TEntity> : ISpecification<TEntity>
{
    public Specification(Expression<Func<TEntity, bool>> predicate)
    {
        _predicate = predicate;
    }

    public bool IsSatisfiedBy(TEntity entity)
    {
        return _predicate.Compile().Invoke(entity);
    }

    private Expression<Func<TEntity, bool>> _predicate;

    public Expression<Func<TEntity,bool>> Predicate{ 
         get{ return _predicate; }
    }
}

你也可以用这种模式做更多的事情,所以我建议调查一下!