我正在嘗試爲我的基類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();
}
}
}
'生成在運行時表達式樹使用泛型參數的實際已知的運行時類型'。很酷,謝謝。我可能很難做到這一點......是否有一個假設/例子可以補充說明我指向正確的方向? –
@MartinHansenLennox:是的,我正在努力增加我的答案。我添加了一些代碼,可以讓你朝着正確的方向前進。如果你看['Expression.MakeMemberAccess'](https://msdn.microsoft.com/en-us/library/system.linq.expressions。expression.makememberaccess(v = vs.110).aspx),應該可以幫助你完成剩下的工作。 – StriplingWarrior
感謝一百萬,非常感謝:) –