我正在尝试为我的DbEntity
基类实现通用存储库 - 其ID可以是int
或guid
。
我几乎让它工作了,但我被困在了存储库的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();
}
}
}
答案 0 :(得分: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));