如何反映T为查询构建表达式树?

时间:2011-01-08 06:47:38

标签: c# linq entity-framework reflection expression-trees

我正在尝试构建一个通用类来处理EF中的实体。这个类与存储库进行对话,但是这个类创建了发送到存储库的表达式。无论如何,我只是想实现一个虚拟方法,它将作为常见查询的基础。具体来说,它将接受一个int,它只需要对相关实体的主键执行查询。

我一直在搞砸它,我已经建立了一个可能会或可能不会起作用的反射。我说是因为我得到一个NotSupportedException消息 LINQ to Entities无法识别方法'System.Object GetValue(System.Object,System.Object [])'方法,而且这个方法不能转换为商店表达式。然后我尝试了另一种方法,它产生了相同的异常但是错误 LINQ to Entities不支持LINQ表达式节点类型'ArrayIndex'。我知道这是因为EF不会像L2S那样解析表达式。

无论如何,我正在跳跃一个有更多经验的人可以指出我正确的方向。我正在用我所做的两次尝试发布整个班级。

public class Provider<T> where T : class {
    protected readonly Repository<T> Repository = null;

    private readonly string TEntityName = typeof(T).Name;

    [Inject]
    public Provider(
        Repository<T> Repository) {
        this.Repository = Repository;
    }

    public virtual void Add(
        T TEntity) {
        this.Repository.Insert(TEntity);
    }

    public virtual T Get(
        int PrimaryKey) {
        //  The LINQ expression node type 'ArrayIndex' is not supported in
        //  LINQ to Entities.
        return this.Repository.Select(
            t =>
                (((int)(t as EntityObject).EntityKey.EntityKeyValues[0].Value) == PrimaryKey)).Single();

        //  LINQ to Entities does not recognize the method
        //  'System.Object GetValue(System.Object, System.Object[])' method,
        //  and this method cannot be translated into a store expression.
        return this.Repository.Select(
            t =>
                (((int)t.GetType().GetProperties().Single(
                    p =>
                        (p.Name == (this.TEntityName + "Id"))).GetValue(t, null)) == PrimaryKey)).Single();
    }

    public virtual IList<T> GetAll() {
        return this.Repository.Select().ToList();
    }

    protected virtual void Save() {
        this.Repository.Update();
    }
}
@Gabe的

更新

这就是我的存储库类:

public class Repository<T> where T : class {
    protected readonly ObjectContext ObjectContext = null;
    private readonly IObjectSet<T> ObjectSet = null;

    [Inject]
    public Repository(
        ObjectContext ObjectContext) {
        this.ObjectContext = ObjectContext;

        this.ObjectSet = this.ObjectContext.CreateObjectSet<T>();
    }

    public virtual void Delete(
        T Entity) {
        this.ObjectSet.DeleteObject(Entity);
    }

    public virtual void Insert(
        T Entity) {
        this.ObjectSet.AddObject(Entity);
    }

    public virtual IQueryable<T> Select() {
        return this.ObjectSet;
    }

    public virtual IQueryable<T> Select(
        Expression<Func<T, bool>> Selector) {
        return this.ObjectSet.Where(Selector);
    }

    public virtual void Update() {
        this.ObjectContext.SaveChanges();
    }
}

方法的名称基于SQL函数,而不是基于LINQ方法,我认为你对我的存储库的运行方式感到困惑。

1 个答案:

答案 0 :(得分:8)

正如Pauli所说,你需要手动创建Expression树,尽管在这种情况下反射不是。以下是编写Get函数的方法:

public virtual T Get(
    int PrimaryKey)
{
    var param = Expression.Parameter(typeof(T));
    // create expression for param => param.TEntityNameId == PrimaryKey
    var lambda = Expression.Lambda<Func<T, bool>>(
        Expression.Equal(
            Expression.Property(param, TEntityName + "Id"),
            Expression.Constant(PrimaryKey)),
        param);
    return this.Repository.Single(lambda);
}

另请注意,您的GetAll功能不需要Select - return Repository.ToList();也可以正常使用。