如何反映T来构建查询的表达式树? [英] How to reflect over T to build an expression tree for a query?

查看:304
本文介绍了如何反映T来构建查询的表达式树?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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


$ b $我已经用螺丝拧紧了,我已经建立了一个可能或可能不工作的反射。我说这是因为我得到一个 NotSupportedException ,其中一个消息是LINQ to Entities不识别方法'System.Object GetValue(System.Object,System.Object [ ])'方法,这个方法不能被转换成存储表达式。所以我尝试了另一种方法,它产生了同样的异常,但出现了错误。 LINQ表达式节点类型'ArrayIndex'不是在LINQ to Entities中支持。我知道这是因为EF不会解析L2S的表达方式。



无论如何,我正在跳跃某人更多的经验可以让我指出正确的方向。我正在发布整个课程,并尝试两次。

  public class Provider< T>其中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){
//
//中不支持LINQ表达式节点类型ArrayIndex LINQ to Entities
return this.Repository.Select(
t =>
(((int)(t as EntityObject).EntityKey.EntityKeyValues [0] .Value)== PrimaryKey))。Single );

// LINQ to Entities不识别方法
//'System.Object GetValue(System.Object,System.Object [])'方法,
//和此方法无法转换为存储表达式。
返回this.Repository.Select(
t =>
((int)t.GetType()。GetProperties()。Single(
p =>
(p.Name ==(this.TEntityName +Id)))。GetValue(t,null))== PrimaryKey))。
}

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

protected virtual void Save(){
this.Repository.Update();对于@Gabe,
}
}

更新



这是我的存储库类型:

  public class储存库< T>其中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>选择(
Expression< Func< T,bool>> Selector){
return this.ObjectSet.Where(Selector);
}

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

方法的名称基于SQL函数,不是在LINQ方法,这是我认为你对我的存储库的功能感到困惑的地方。

解决方案

作为Pauli在这种情况下,您需要手动创建表达式树,尽管反射不是。以下是如何编写您的 Get 函数:

  public virtual T Get (
int PrimaryKey)
{
var param = Expression.Parameter(typeof(T));
//为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 函数不需要选择 - return Repository.ToList(); 也可以正常工作。


I'm trying to build a generic class to work with entities from EF. This class talks to repositories, but it's this class that creates the expressions sent to the repositories. Anyway, I'm just trying to implement one virtual method that will act as a base for common querying. Specifically, it will accept a an int and it only needs to perform a query over the primary key of the entity in question.

I've been screwing around with it and I've built a reflection which may or may not work. I say that because I get a NotSupportedException with a message of 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. So then I tried another approach and it produced the same exception but with the error of The LINQ expression node type 'ArrayIndex' is not supported in LINQ to Entities. I know it's because EF will not parse the expression the way L2S will.

Anyway, I'm hopping someone with a bit more experience can point me into the right direction on this. I'm posting the entire class with both attempts I've made.

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();
    }
}

UPDATE for @Gabe

This is what my repository class looks like:

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();
    }
}

The names of the methods are based on the SQL functions, not on the LINQ methods, which is where I think you're getting confused on how my repository functions.

解决方案

As Pauli alludes to, you need to manually create Expression trees, although reflection isn't necessary in this case. Here's how you could write your Get function:

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);
}

Also, note that your GetAll function doesn't need Select -- return Repository.ToList(); will work just as well.

这篇关于如何反映T来构建查询的表达式树?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆