帮我解决架构问题

时间:2011-07-26 22:36:15

标签: c# entity-framework

以下是简单的代码段:

 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数据模型设计器中创建一个抽象实体,映射到空,并将其标记为所有其他实体的基本类型,但它要求映射即表。我尝试使用复杂类型 - 这不会让我继承它。

所以,请告诉我最有效的方法来实现这个目标

4 个答案:

答案 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接口(即如果您不拥有它们),否则开销是不必要的。