2011-01-08 42 views
1

我试图建立一个通用类来处理来自EF的实体。这个类与储存库对话,但是这个类创建发送到储存库的表达式。无论如何,我只是试图实现一个虚拟方法,它将作为普通查询的基础。具体来说,它将接受一个int,它只需要对相关实体的主键执行查询。如何反思T为查询构建表达式树?

我一直在使用它,我已经建立了一个可能或可能不起作用的反射。我说因为我得到一个NotSupportedException消息LINQ to Entities不识别方法'System.Object GetValue(System.Object,System.Object [])'方法,并且此方法不能转换为存储表达式。因此,然后我尝试了另一种方法,它产生了相同的异常,但与的错误LINQ表达式节点类型'ArrayIndex'在LINQ to Entities中不受支持。我知道这是因为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(); 
    } 
} 

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方法,这是我认为你对我的存储库功能有困惑的地方。

+0

它看起来像你认为`Select`基于`Get`函数完成`Where`的工作。 “Where”的作用是选择要返回的行(例如具有匹配主键的行),而“Select”只是选择返回哪些列(通常全部在EF中)。 – Gabe 2011-01-08 07:42:25

+0

@加贝,请看我上面的更新,我解释了为什么。 – Gup3rSuR4c 2011-01-08 22:45:31

回答

8

正如泡利所暗示的那样,您需要手动创建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();将工作一样好。