实体框架核心 - 使用表达式树界面,参数

问题描述 投票:2回答:1

我会很感激一些帮助,下面的场景。我有以下类别:

public class Product : IHasPrice
{
    public string Title { get; set; }
    public int Price { get; set; }
    public string CustomerId { get; set; }

}

public interface IHasPrice
{
    int Price { get; set; }
}

public class ProductProvider
{
    public ProductProvider()
    {
    }

    public IEnumerable<Product> GetByCustomer(string customerId, Expression<Func<IHasPrice, bool>> predicate = null)
    {
        using (var db = new ApplicationDbContext())
        {
            var queryable = db.Products.Where(p => p.CustomerId == customerId);
            if (predicate != null)
            {
                return queryable.Where(predicate).ToList();
            }
            else
            {
                return queryable.ToList();
            }
        }
    }
}

我想启用使用ProductProvider的方式,你只能通过客户选择,但你还可以过滤对你喜欢的(只有对价)任何形式的价格。这个例子没有工作,因为queryable.Where预计用typeof Expression(Func(Product, bool))参数。有没有办法做到这一点还是必须的价格过滤之前取的数据存储?

c# entity-framework entity-framework-core expression-trees
1个回答
2
投票

由于IQueryable<out T>接口是协变,所传递的lambda表达式可以直接与Where方法中使用:

var query = queryable.Where(predicate);

唯一的问题是,现在的结果查询的类型是IQueryable<IHasPrice>。你可以将其重新使用IQueryable<Product>方法Queryable.Cast

var query = db.Products.Where(p => p.CustomerId == customerId);
if (predicate != null)
    query = query.Where(predicate).Cast<Product>(); // <--
return query.ToList();

经过测试,与最新的EF核心2.2(在一些早期版本可能会失败)工作。


另一种解决方案是由“调用”它的Expression<Func<IHasPrice, bool>>的预期Expression<Func<Product, bool>>转换:

var query = db.Products.Where(p => p.CustomerId == customerId);
if (predicate != null)
{
    var parameter = Expression.Parameter(typeof(Product), "p");
    var body = Expression.Invoke(predicate, parameter);
    var newPredicate = Expression.Lambda<Func<Product, bool>>(body, parameter);
    query = query.Where(newPredicate);
}
return query.ToList();
© www.soinside.com 2019 - 2024. All rights reserved.