2011-01-08 43 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();將工作一樣好。