实体框架:FindBy(列名)按表达式树选择任意列

本文关键字:表达式 选择 任意列 列名 框架 FindBy 实体 | 更新日期: 2023-09-27 17:57:13

我有一个非常简单的代码,我在这里试图实现什么。

基本上,这里的想法是能够进行简单的FindBy(x => x.<the_column_name>, <the value>);因此我不必通过仅更改列名来复制粘贴相同的查询。

现在,我不断收到来自 LINQ 的异常,说LINQ to Entities does not recognize the method 'System.String Invoke(Spunky.Entities.User)' method, and this method cannot be translated into a store expression

这可能吗?或者,也许我们还没有 EF 6.1

public class UsersRepository
{
  private Lazy<IDataContext> context;
  public UsersRepository()
    : this(() => new DataContext())
  {
  }
  public UsersRepository(Func<IDataContext> context)
  {
    this.context = new Lazy<IDataContext>(context);
  }
  public IQueryable<User> Find(int id)
  {
    return FindBy(u => u.Id, id);
  }
  public IQueryable<User> Find(string username)
  {
    return FindBy(u => u.Username, username);
  }
  public IQueryable<User> FindBy<T>(Func<User, T> property, T value)
  {
    return context.Value
            .Users
            .Where(u => property.Invoke(u).Equals(value));
  }
}

实体框架:FindBy(列名)按表达式树选择任意列

如果您更改签名

IQueryable<User> FindBy(Expression<Func<User, bool>> predicate)
{
    return context.Users.Where(predicate);
}

你可以打电话

return FindBy(u => u.Username == username);

代码几乎不会更改,但您不需要制造表达式。

你必须输入一个表达式(而不是Func),因为表达式可以转换为SQL。Func只是一个 .Net 委托,不存在 SQL 等效项。

你需要构造一个表达式树 linq 到实体可以转换为 sql:

public IQueryable<T> FindBy<TKey>(Expression<Func<T,TKey>> memberExpression, object value)
{
    var parameterVisitor = new ParameterVisitor(memberExpression);
    var parameter = parameterVisitor.Parameter;
    var constant = Expression.Constant(value);
    var equal = Expression.Equal(memberExpression,constant);
    var predicate = Expression.Lambda(equal, parameter);
    return context.Value.Users.Where(predicate);
}
public class ParameterVisitor : ExpressionVisitor
{
   public ParameterExpression Parameter { get;set;}
   public ParameterVisitor(Expression expr)
   {
       this.Visit(expr);
   }
   protected override VisitParameter(ParameterExpression parameter)
   {
        Parameter = parameter;
        return parameter;
    }
}

仍然未经测试。

编辑:代码已更正。