使用泛型类型执行EntityFramework Core LINQ查询



我正在尝试为一个服务实现一些基类,该服务使用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上下文。

上面的代码(或者与本例非常相似的代码为了清晰起见过于简化(失败了,实体框架无法翻译表达式。

到目前为止,唯一有效的方法是在每个派生类中为.Where子句实现一个具有实际非泛型类型的重写,但我希望避免重复实现相同的代码。

另一个想法是让实体类从某个基类派生,但由于它们是自动生成的,这可能会有问题。

任何新的想法都将不胜感激。

您已经获得了生成表达式的所有代码,以便根据已知值检查ID。只需将其放入Get方法中,并使用具有pk值的Expression.Constant,而不是pkExprExpression.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();
}

最新更新