使用EF的通用存储库实现

时间:2011-04-25 14:25:14

标签: entity-framework entity-framework-4 repository repository-pattern

对于简单的存储库

public interface ISimpleRepository<T>
{
    IApplicationState AppState { get; set; }
    void Add(T instance);
    void Delete(T instance);
    void Delete(Guid rowGuid);
    IQueryable<T> GetAll();
    T Load(Guid rowGuid);
    void SaveChanges();
    void Update(T instance);
}

我对类Load()的特定存储库的Product方法的实现可能如下所示:

    public Product Load(Guid rowid)
    {
        return (from c in _ctx.Products where c.id == rowid select c).FirstOrDefault();
    }

现在假设我的存储库实现类如下所示:

public class EntityFrameworkProductsProvider : IRepository<Product> ...

如果我有几十个或几百个这样的小而简单的实体在做CRUD时会使用相同的行为(使用相同的方法实现)怎么办?我当然不想创建一个类来为每个人实现IRepository。

我想要这样的事情:

public class EntityFrameworkDefaultProvider<T> : IRepository<T> ...

但是我不知道如何实现LINQ Select表达式,因为我当然不能写from e in _ctx.T where e...或者我?

我还没有碰到这种情况,因为到目前为止我只有非常具体的实体和自定义存储库实现。

4 个答案:

答案 0 :(得分:4)

因为您使用标记了您的问题,我假设您使用的是ObjectContext API。 ObjectContext提供的方法CreateObjectSet<T>相当于Set<T>上的DbContext

这个问题实际上是重复的:

答案 1 :(得分:3)

您可以撰写_ctx.Products,而不是撰写_ctx.Set<T>。这解决了问题的一半(您需要向存储库添加通用约束where T: class

然后,如果rowid是对象的键,则可以使用_ctx.Set<T>.Find(rowid)而不是LINQ查询来按Id检索。

或者,您可以创建具有IHaveId属性的基接口BaseEntity(或任何您喜欢的Id类),然后将其作为T的通用约束添加,因此您可以在查询中使用它。

答案 2 :(得分:2)

答案 3 :(得分:1)

我知道在使用DbContext API的EF4.1中可以实现这一点,在上下文中你有一个“Set”方法,它可以获得与类型T对应的实体集。这样,你可以让你的存储库像这样:

public class EntityFrameworkDefaultProvider<T> : IRepository<T> where T:class
{
    public T Load(Guid rowId)
    {
        return _context.Set<T>().Find(rowId);
    }
}

还有一句话:我认为你可以使用这种语法:

return _ctx.Products.FirstOrDefault(c=>c.id == rowid);

获取您想要的实体而不是使用(from ... in ...)。它更清楚(在我看来):))

希望这有帮助