我有一个非常简单的代码,我在这里试图实现什么。
基本上,这里的想法是能够进行简单的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));
}
}
如果您更改签名
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;
}
}
仍然未经测试。
编辑:代码已更正。