表达式:当我有表达式获取ID时,ID-get-get选择器?

时间:2011-02-21 15:32:04

标签: c# linq-to-entities expression-trees

我有一个LINQ-to-Entities的通用基础存储库类,可以执行基于ID选择实体的操作。

为了对其进行子类化,您需要实现这两个:

protected override Expression<Func<User, bool>> GetByIDSelector(int id)
{
  return u => u.UserID == id;
}

protected override Expression<Func<User, int>> KeySelector
{
  get { return u => u.UserID; }
}

我想要KeySelector(用于默认排序顺序)。

我的'ID by ID'方法如下所示:

public virtual TDataModel GetByID(TKey id)
{
  var entity = SetProvider.Set<TDataModel>().Where(GetByIdSelector(id)).SingleOrDefault();

  if (entity == null)
  {
    throw new EntityNotFoundException<TDataModel>(id);
  }

  return entity;
}

GetByIdSelector看起来像这样,应该将KeySelector表达式转换为可以按ID选择的表达式。

private Expression<Func<TDataModel, bool>> GetByIdSelector(TKey id)
{
  return Expression.Lambda<Func<TDataModel, bool>>
  (
    Expression.Equal(KeySelector.Body,
    Expression.Constant(id)), 
    KeySelector.Parameters.Single()
  );
}

但是,实体框架会抛出一个异常,即传入的参数未绑定到查询。

  

参数“u”未绑定在指定的LINQ to Entities查询表达式中。

有没有什么方法可以干净地重用KeySelector表达式而无需重建整个事物?

1 个答案:

答案 0 :(得分:3)

这不起作用的原因是因为每次调用this.KeySelector时,它都会创建一个全新的lambda表达式(因此对KeySelector.Parameters.Single()的调用与用于{的参数不同。 {1}})。将该表达式缓存到变量中,如下所示,它将起作用。

KeySelector.Body

我可能会做的是修复KeySelector属性中的代码以使用固定值,以便检索的值始终是相同的实例。

示例:

private Expression<Func<TDataModel, bool>> GetByIdSelector(TKey id)
{
    var keySelector = KeySelector;
    return Expression.Lambda<Func<TDataModel, bool>>(
        Expression.Equal(
            keySelector.Body,
            Expression.Constant(id)
        ), 
        keySelector.Parameters.Single()
    );
}

然后,如果你这样做 - 你的旧代码GetByIdSelector实际上并不比我上面的版本差。