Entity Framework 核心-使用表达式树以接口作为参数
Entity Framework Core- Use Expression Tree With Interface As Parameter
对于以下场景,我将非常感谢您的帮助。
我有以下 类:
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
的使用方式,您只能 select 按客户,但您也可以按您喜欢的任何方式过滤价格(并且仅在价格)。
此示例不起作用,因为 queryable.Where
需要类型为 Expression(Func(Product, bool))
的参数。有没有办法做到这一点,或者我必须在过滤价格之前将数据提取到内存中?
由于IQueryable<out T>
接口是协变的,传递的lambda表达式可以直接用Where
方法使用:
var query = queryable.Where(predicate);
唯一的问题是现在结果查询的类型是IQueryable<IHasPrice>
。您可以使用 Queryable.Cast
方法将其恢复为 IQueryable<Product>
:
var query = db.Products.Where(p => p.CustomerId == customerId);
if (predicate != null)
query = query.Where(predicate).Cast<Product>(); // <--
return query.ToList();
已测试并使用最新的 EF Core 2.2(在某些早期版本中可能会失败)。
另一种解决方案是通过 "invoking" 将 Expression<Func<IHasPrice, bool>>
转换为预期的 Expression<Func<Product, bool>>
it:
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();
对于以下场景,我将非常感谢您的帮助。 我有以下 类:
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
的使用方式,您只能 select 按客户,但您也可以按您喜欢的任何方式过滤价格(并且仅在价格)。
此示例不起作用,因为 queryable.Where
需要类型为 Expression(Func(Product, bool))
的参数。有没有办法做到这一点,或者我必须在过滤价格之前将数据提取到内存中?
由于IQueryable<out T>
接口是协变的,传递的lambda表达式可以直接用Where
方法使用:
var query = queryable.Where(predicate);
唯一的问题是现在结果查询的类型是IQueryable<IHasPrice>
。您可以使用 Queryable.Cast
方法将其恢复为 IQueryable<Product>
:
var query = db.Products.Where(p => p.CustomerId == customerId);
if (predicate != null)
query = query.Where(predicate).Cast<Product>(); // <--
return query.ToList();
已测试并使用最新的 EF Core 2.2(在某些早期版本中可能会失败)。
另一种解决方案是通过 "invoking" 将 Expression<Func<IHasPrice, bool>>
转换为预期的 Expression<Func<Product, bool>>
it:
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();