更新存储库模式的概念

Update Concept for Repository Pattern

我目前正在创建一个实施存储库模式的概念验证 应用程序。我决定使用 classic ADO.NETEntity Framework 作为我的示例 ORM。这是目前我的 IRepository 和 IUnitOfWork 接口的实现方式。

public interface IUnitOfWork : IDisposable
{
    IEmployeeRepository Employees { get; }

    int Complete();
}

public interface IRepository<TEntity> where TEntity : class
{
    TEntity Get(int id);
    IEnumerable<TEntity> GetAll();
    IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate);

    TEntity SingleOrDefault(Expression<Func<TEntity, bool>> predicate);

    void Add(TEntity entity);
    void AddRange(IEnumerable<TEntity> entities);

    void Remove(TEntity entity);
    void RemoveRange(IEnumerable<TEntity> entities);
}

我的更新对象的 Entity Framework 实现一切顺利,因为它有一个内置的 ChangeTracker class 检查对象的状态。

static void Main(string[] args)
{
    var context = new RPContextDbFactory().CreateDbContext(null);

    using (var unitOfWork = new Data.EF.UnitOfWork(context))
    {
        //using Entity Framework
        var employee = unitOfWork.Employees
            .Get(1);
        employee.FirstName = "Foo";

        unitOfWork.Complete(); // <-- Calls DbContext.SaveChanges()
    }
}

我的问题是如何在 classic ADO.NET 实现上实现相同的概念,因为它没有像 EF 那样的 ChangeTracker class。

static void Main(string[] args)
{
    var builder = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);

    IConfigurationRoot configuration = builder.Build();


    var connectionString = configuration.GetConnectionString("RPContext");

    using (var unitOfWork = new Data.StoredProcedures.UnitOfWork(connectionString))
    {
        //using classic ADO.NET
        var employee = unitOfWork.Employees
            .Get(1);
        employee.FirstName = "Foo";

        unitOfWork.Complete(); //<-- Nothing will happen. 
    }
}

//UnitOfWork implementation for my classic ADO.NET
public class UnitOfWork : IUnitOfWork
{
    public UnitOfWork(string connectionString)
    {
        Employees = new EmployeeRepository(connectionString);
    }

    public IEmployeeRepository Employees { get; private set; }

    public int Complete()
    {
        throw new NotImplementedException();
    }

    public void Dispose()
    {
        throw new NotImplementedException();
    }
}

我在其他网站上看到的一个建议是在我的 ADO.NET 命名空间的 UnitOfWork class 中实现一种 ChangeTracker 逻辑,但我不太确定如何实现它。我的 UoW 如何知道更改了哪些对象?

我不明白同时使用 ADO.NET 和 EF 的必要性。单独使用 EF 就可以了。

无论如何,我建议不要为 ADO.NET 自己实施 UoW。它需要大量工作并且容易出错,最后你会发现你做错了。如果您真的想使用 UoW,请改用 EF(或 NHibernate 或其他)。为什么要重新发明轮子?如果你决定自己实现它,你实际上是在编写自己的 ORM,它被认为是 anti pattern.

如果您想使用 ADO.NET 实现更新功能,那么您只需在 IRepository 中实现 void Update(TEntity entity); 方法并从调用代码中显式调用它。不要让 IUnitOfWork 自动执行此操作。

编辑:回复您的一些评论 -

The classic ADO.NET ORM does not have this feature which is why I am having problems with updating objects.

ADO.NET 不是 ORM。与RDBMS通信简单又核心API。所有 ORM 都在内部使用它。

it also defeats one of the key purpose of the repository pattern which is to decouple your application from any ORM frameworks.

不是,隐藏ORM不是Repository的objective。抽象数据库逻辑是。通过这样做,您可以模拟存储库,并且您的其他代码变得可测试。切换 ORM 是非常罕见的决定。存储库使该过程变得简单;当然。但是,这仍然不是存储库的责任。其实Repository跟ORM没有关系

Repository pattern must still be implemented for all of them.

可能是;根据业务需要。像 EF 这样的完整 ORM 本身就是存储库。因此,是否在其上再添加一个抽象是设计决策。有些确实添加了它;有些人更喜欢直接使用 ORM。两种方法都有优点和缺点。

Creating an Update method is incorrect because your repository should not concern itself with the semantics of your database.

那就得自己实现ORM了。许多 ORM 是开源的。参考 Git Hub 上的 Dapper-Contrib 代码。它支持有限的UoW;好的开始。希望对你有帮助。

我仍然坚持(根据我自己的经验)不开发自己的 ORM。