2016-03-09 44 views
1

我正在嘗試爲我的基類DbEntity實現一個通用存儲庫 - 其ID可能是int或​​。我可以爲通用資源庫實現PK類型參數嗎?

我幾乎有它的工作,但我卡在存儲庫的SelectByID()方法。

語法table.Find(id)工作得很好。

但語法SingleOrDefault(i => i.ID == id)沒有。它給了我operator '=='cannot be applied to operants of type PKT and PKT

但我想用第二個版本(因爲它可以讓我加載相關實體Include()。)

我已經使用PKT沒有限制嘗試。
我試過使用struct約束,但我仍然得到相同的錯誤。

我應該如何實施?

更新

很多從@StriplingWarrior幫助後,這裏是我想出了:

public virtual T SelectByID(PKT id, params Expression<Func<T, object>>[] includeExpressions) 
{ 
    if (includeExpressions.Any()) 
    { 
     var set = includeExpressions.Aggregate<Expression<Func<T, object>>, IQueryable<T>> 
        (table, (current, expression) => current.Include(expression)); 

     ParameterExpression parameter = Expression.Parameter(typeof(T), "s"); 
     PropertyInfo propertyInfo = typeof(T).GetProperty("ID"); 
     MemberExpression memberExpression = Expression.MakeMemberAccess(parameter, propertyInfo); 
     ConstantExpression constantExpression = Expression.Constant(id, typeof(PKT)); 
     BinaryExpression binaryExpression = Expression.Equal(memberExpression, constantExpression); 
     Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(binaryExpression, parameter); 

     return set.SingleOrDefault(lambda); 

    } 
    return table.Find(id); 
} 

基地實體

public interface IDBEntity<PKT> 
     where PKT : struct 
    { 
     PKT ID { get; set; } 
     string Title { get; set; } 
    } 

    public class DBEntity<PKT> : IDBEntity<PKT> 
     where PKT : struct 
    { 
     [Key] 
     [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
     public PKT ID { get; set; } 
     public virtual string Title { get; set; } 
    } 

用法

public class Car : DBEntity<Guid> 
    { 
     public string Colour { get; set; } 
    } 
    public class Pet : DBEntity<int> 
    { 
     public bool FurryOrNot { get; set; } 
    } 

通用庫

public class GenericRepository<T, PKT> : IGenericRepository<T, PKT> 
     where T : DBEntity<PKT> 
     where PKT : struct 
    { 
     private ApplicationDbContext db = null; 
     private DbSet<T> table = null; 


     public GenericRepository() 
     { 
      db = new ApplicationDbContext(); 
      table = db.Set<T>(); 
     } 

     public virtual T SelectByID(PKT id, params Expression<Func<T, object>>[] includeExpressions) 
     { 
      if (includeExpressions.Any()) 
      { 
       var set = includeExpressions.Aggregate<Expression<Func<T, object>>, IQueryable<T>> 
         (table, (current, expression) => current.Include(expression)); 

       return set.SingleOrDefault(s => s.ID == id); 

      } 
      return table.Find(id); 
     } 


     public virtual IQueryable<T> AllAsQueryable(params Expression<Func<T, object>>[] includeExpressions) 
     { 
      return includeExpressions.Aggregate<Expression<Func<T, object>>, IQueryable<T>> 
       (table, (current, expression) => current.Include(expression)); 
     } 



     public virtual IQueryable<T> AllWhereAsQueryable(Expression<Func<T, bool>> wherePredicate, params Expression<Func<T, object>>[] includeExpressions) 
     { 
      return AllAsQueryable(includeExpressions).Where(wherePredicate); 
     } 


     public virtual void Create(T obj) 
     { 
      table.Add(obj); 
      Save(); 
     } 



     public virtual void Edit(T obj) 
     { 
      table.Attach(obj); 
      db.Entry(obj).State = EntityState.Modified; 
      Save(); 
     } 



     public void Delete(object id) 
     { 
      T existing = table.Find(id); 
      table.Remove(existing); 
      Save(); 
     } 



     public virtual void Save() 
     { 
      db.SaveChanges(); 
     } 



     public virtual void Dispose(bool disposing) 
     { 
      if (disposing) 
      { 
       db.Dispose(); 
      } 
     } 
    } 

回答

1

你遇到了此問題的原因是因爲在編譯時==運算符來獲取綁定基於已知有關的信息嘗試編譯時的類,並不多。

您可能想嘗試使用.Equals()來代替。我不確定這是否會起作用。

過去我已經討論過這種方式,它是在運行時通過生成表達式樹來使用泛型參數的實際已知運行時類型。所以,與其這樣:

return set.SingleOrDefault(s => s.ID == id); 

...這將是這樣的:

var parameter = Expression.Parameter("s", typeof(T)); 
return set.SingleOrDefault(
    Expression.Lambda<Func<T, bool>>(
     Expression.Equal(
      /*make an expression that gets the ID property from parameter*/, 
      Expression.Constant(id, typeof(PKT)), 
     parameter)); 
+0

'生成在運行時表達式樹使用泛型參數的實際已知的運行時類型'。很酷,謝謝。我可能很難做到這一點......是否有一個假設/例子可以補充說明我指向正確的方向? –

+0

@MartinHansenLennox:是的,我正在努力增加我的答案。我添加了一些代碼,可以讓你朝着正確的方向前進。如果你看['Expression.MakeMemberAccess'](https://msdn.microsoft.com/en-us/library/system.linq.expressions。expression.makememberaccess(v = vs.110).aspx),應該可以幫助你完成剩下的工作。 – StriplingWarrior

+0

感謝一百萬,非常感謝:) –

相關問題