以下是简单的代码段:
public interface IRepository<T>
{
T Get(int id);
}
public class Repository<T> : IRepository<T> where T : class
{
private readonly IRepositoryContext _repositoryContext;
private IObjectSet<T> _objectSet;
public Repository(IRepositoryContext repositoryContext)
{
_repositoryContext = repositoryContext;
_objectSet = repositoryContext.GetObjectSet<T>();
}
public virtual T Get(int id)
{
return ObjectSet.First(x=> x.Id == id)
// that wouldn't work because there is no guarantee that T entity has Id property
}
现在,正如您所见,我可以为任何实体对象实例化Repository并使用已定义的方法(尽管在示例中我们只有Get()。但我不能在表达式中使用任何约束,除非我创建非抽象T
基于IRepository<T>
的每个实体的类,然后按照我想要的方式实现方法。
但是如果我需要使用类似Get
的方法,那么实现对于所有实体(每个实体都有一个Id)保持相同的方法会怎样。
怎么做?
我想,我可以在EF数据模型设计器中创建一个抽象实体,映射到空,并将其标记为所有其他实体的基本类型,但它要求映射即表。我尝试使用复杂类型 - 这不会让我继承它。
所以,请告诉我最有效的方法来实现这个目标
答案 0 :(得分:4)
知道您的对象中是否存在ID,这不是存储库的角色。
大多数存储库都像这样实现Single
方法
public T Single( Expression<Func<T, bool>> predicate ) {
return ObjectSet.Single<T>( predicate );
}
答案 1 :(得分:1)
执行所要求的最佳方法可能是构建自定义表达式。像这样:
public Expression<Func<T, bool>> GetIdEqualsExpression(int id)
{
var idProp = typeof(T).GetProperty("ID");
var param = Expression.Parameter(typeof(T), "t");
return Expression.Lambda<Func<T, bool>>(
Expression.Equal(Expression.PropertyOrField(param, "ID"),
Expression.Constant(id)), param);
}
public virtual T Get(int id)
{
return ObjectSet.AsQueryable().Single(GetIdEqualsExpression(id));
}
也就是说,Bertrand说明可能应该由调用代码负责提供表达式,因此您不会冒运行时异常的风险。
答案 2 :(得分:0)
您可以使用界面:
公共接口IEntity { int Id {get; } }
然后代替“where T:class”你可以做“where T:IEntity”,任何对象都有一个可检索的Id。
答案 3 :(得分:0)
如果每个实体都具有Id属性,则可以创建一个公开Id属性的接口,使每个实体实现接口。
//Let's call the interface IIDInterface
public interface IIDInterface
{
int Id { get; }
}
// Now, suppose one of your entity classes is called: EntityOne
public class EntityOne : IIDInterface
{
// .. class constructors etc.
// the IIDInterface interface method implementation
public int Id
{
get
{
// getter implementation goes here
}
}
// .. other members of the class
}
然后你可以在Get的实现中转换为接口,如果转换成功,则使用.Id属性。 Get函数变为:
public virtual T Get(int id)
{
if(T is IIDInterface)
return ObjectSet.First(x => ((IIDInterface)x).Id == id)
return default(T);
}
修改强>
另一个解决方案可能是使用反射并使用T对象的Id属性(如果有)。但这样做可能会慢一些,我认为除非您无法修改实体对象以实现IIDInterface接口(即如果您不拥有它们),否则开销是不必要的。