使用泛型类型执行 EntityFramework Core LINQ 查询
Posted
技术标签:
【中文标题】使用泛型类型执行 EntityFramework Core LINQ 查询【英文标题】:Executing EntityFramework Core LINQ query with generic types 【发布时间】:2022-01-15 12:35:46 【问题描述】:我正在尝试为使用 EF Core 和泛型从数据库中获取对象的服务实现一些基类。 考虑以下类:
/// <summary>
/// Base entity getter service
/// </summary>
/// <typeparam name="TEntity">The database entity type</typeparam>
/// <typeparam name="TPK">The primary key type for example: int</typeparam>
class Service<TEntity, TPK>
protected Func<TEntity, TPK, bool> pkFinder;
public Service(string pkname)
var entityExpr = Expression.Parameter(typeof(TEntity), "instance");
var propertyExpr = Expression.Property(entityExpr, pkname);
var pkExpr = Expression.Parameter(typeof(TPK), "value");
var eqExpr = Expression.Equal(propertyExpr, pkExpr);
pkFinder = Expression.Lambda<Func<TEntity, TPK, bool>>(eqExpr, entityExpr, pkExpr).Compile();
public TEntity Get(TPK pk)
return ctx.Set<TEntity>().Where(e=>pkFinder.Invoke(e, pk)).SingleOrDefault();
pkname 参数是保存该实体主键的属性的名称(通常为“Id”)
ctx 对象是 EF 上下文。
上面的代码(或与此示例非常相似的代码为了清楚起见被过度简化了)失败,Entity Framework 无法翻译表达式。
到目前为止唯一有效的是在每个派生类中为具有实际非泛型类型的 .Where 子句实现覆盖,但是我想避免一遍又一遍地重新实现相同的代码。
另一个想法是让实体类派生自某个基类,但由于它们是自动生成的,这可能会有问题。
任何新想法都将不胜感激。
【问题讨论】:
您已经获得了用于生成表达式以根据已知值检查 ID 的所有代码。只需将其放入您的Get
方法中,并为您的 pkExpr
使用带有 pk
值的 Expression.Constant
而不是 Expression.Parameter
。
【参考方案1】:
您已经获得了生成表达式以根据已知值检查 ID 的所有代码。只需将其放入您的 Get
方法中,并为您的 pkExpr
使用带有 pk
值的 Expression.Constant
而不是 Expression.Parameter
。
我还没有测试过,但是这样的东西应该可以工作:
private readonly string pkname;
public Service(string pkname)
this.pkname = pkname;
public TEntity Get(TPK pk)
var entityExpr = Expression.Parameter(typeof(TEntity), "instance");
var propertyExpr = Expression.Property(entityExpr, pkname);
var pkExpr = Expression.Constant(pk, typeof(TPK));
var eqExpr = Expression.Equal(propertyExpr, pkExpr);
var pkFinder = Expression.Lambda<Func<TEntity, bool>>(eqExpr, entityExpr);
return ctx.Set<TEntity>().Where(pkFinder).SingleOrDefault();
【讨论】:
但这不是意味着我必须在每次执行时重新编译表达式吗?还是说 EF 每次都会重新编译? 是的,它有效并且对性能的影响微不足道。非常感谢。其中之一是“我以前怎么没想到……”。应该是很晚了。 ;-) 是的,要回答您之前的问题,表达式根本不需要“编译”。它只需要构建,然后由实体框架解释,如果你有一个硬编码的表达式,所有这些都会发生。如果您查看在代码中说e => e.Id == id
时生成的 IL 代码,它实际上是在生成对所有 Expression
方法的调用。以上是关于使用泛型类型执行 EntityFramework Core LINQ 查询的主要内容,如果未能解决你的问题,请参考以下文章