更新存储库模式的概念

时间:2018-06-07 02:03:14

标签: c# .net-core repository-pattern

我目前正在创建一个实现存储库模式的概念验证应用程序。我决定使用经典ADO.NET 实体框架作为我的示例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 类来检查对象的状态。

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()
    }
}

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

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类中实现ChangeTracker逻辑,但我不确定如何实现它。我的UoW将如何知道哪些对象被更改了?

1 个答案:

答案 0 :(得分:1)

我不明白是否需要同时使用ADO.NET和EF。仅EF应该这样做。

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

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

编辑:回复您的部分评论

  

经典的ADO.NET ORM没有此功能,这就是我在更新对象时遇到问题的原因。

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

  

它也破坏了存储库模式的一个关键目的,即将应用程序与任何ORM框架分离。

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

  

仍然必须为所有这些实现存储库模式。

可能是;取决于业务需求。像EF这样的完整ORM本身就是Repository。因此,设计决定是否在其上再添加一个抽象。有些人会加上它;有些人喜欢直接使用ORM。这两种方法都有其优点和缺点。

  

创建Update方法不正确,因为您的存储库不应该关注数据库的语义。

您必须自己实施ORM。许多ORM都是开源的。请参阅Git Hub上的Dapper-Contrib代码。它支持有限的UoW;好开始。希望它可以帮助你。

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