1

过去两天我一直在阅读 UnitOfWork 模式,但没有正确理解。

我为每个班级都有一个存储库。例如。员工、考勤、工资、部门、地址等

存储库意味着 - 这些类中的每一个都有自己的 CRUD 操作(创建自己的数据库连接)。这些创建单独的数据库连接并插入。

当我想以原子方式执行多个操作时会出现问题。例如。在单个事务中插入员工和地址。但是我的存储库不允许这样做,因为 Employee 只负责管理 Employee 表。

我可以使用 System.Transactions 但这会让我发疯,因为单个事务有许多数据库连接。

UoW 是否适用于我的情况,但会做出一些改变?

编辑:

我的示例代码

public class AccountTransactionManager
{
    Properties.Settings settings = new Properties.Settings();

    public void InsertAccountTransaction(AccountTransaction accountTransaction)
    {
        SqlParameter AccountId = new SqlParameter { ParameterName = "@AccountId", Value = accountTransaction.AccountId, Direction = ParameterDirection.Input, SqlDbType = SqlDbType.Int };
        SqlParameter PAYMENT_DATE = new SqlParameter { ParameterName = "@PAYMENT_DATE", Value = accountTransaction.PAYMENT_DATE, Direction = ParameterDirection.Input, SqlDbType = SqlDbType.DateTime };
        SqlParameter CURRENT_BALANCE = new SqlParameter { ParameterName = "@CURRENT_BALANCE", Value = accountTransaction.CURRENT_BALANCE, Direction = ParameterDirection.Input, SqlDbType = SqlDbType.Money };

        Helper.SqlHelper.Execute(settings.SQLConnectStr
            , (tran) =>
            {
                Helper.SqlHelper.ExecuteNonQuery(tran, CommandType.StoredProcedure, "usp_AccountTransactionInsert", AccountId, PAYMENT_DATE, CURRENT_BALANCE);
            });
    }
}

SqlHelper 代码

public static void Execute(string connectionString, Action<SqlTransaction> CallBack)
{
    if (CallBack == null)
        return;

    using (var con = new SqlConnection(connectionString))
    {
        con.Open();
        using (var tran = con.BeginTransaction())
        {
            #region Call procedures

            try
            {
                CallBack(tran);
                tran.Commit();
            }
            catch (SqlException ex)
            {
                tran.Rollback();
                throw ex;
            }
            finally
            {
                con.Close();
            }

            #endregion
        }
    }
}

需求将非常频繁地变化。所以我应该使用任何 ORM 还是创建自己的存储库。我可以在 ORM 中使用存储过程吗?

4

2 回答 2

2

你有一些非常错误的假设。首先,仅仅因为您有两个存储库,并不意味着如果您同时使用它们就有两个数据库连接。数据库连接由大多数 ORM 池化,例如 Entity Framework 和 nHibernate。因此,您不知道如何处理连接,但您通常可以放心,当您调用 SaveChanges 时,它将具有隐含的事务并作为单个原子操作发生。

其次,您忽略了 ORM 的主要优势之一,即导航属性和集合。如果您有一个 Employee 表,那么它应该有一个地址导航属性或地址集合。

因此,假设您要插入一个新员工。您创建一个新的员工实体,然后创建一个新的地址实体,然后将地址添加到员工,然后将员工添加到您的 ORM。当您调用 Commit 或 SaveChanges 或任何导致您的 ORM 更新的东西时,它会更新两个实体并作为单个事务发生。

同样,如果您添加多个员工,当您调用 SaveChanges 时,所有员工都将作为单个事务添加。

如果您认为可能需要分布式事务,您实际上只需要使用 System.Transaction。或者,您确实有一个无法在单个工作单元中完成的多步骤过程。

您所说的大部分内容都是基于每个存储库都是它自己的独立工作单元的假设,这根本不是必要的假设。UnitOfWorks 可以在您的所有存储库之间共享。如果您使用依赖注入,这将更容易实现。

编辑:

根据您的编辑,我看到您没有使用 ORM,而是使用存储库来处理您的 DAL。我所说的一些内容仍然适用,您不需要每个存储库都有自己的连接,并且您不需要让存储库只处理单个实体,因为实体也具有可以管理的相关实体。

关于 UnitOfWork 要记住的重要一点是它是一种实体缓存。您向它添加或更新脏实体,它不会一个一个地保存它们......相反,它会一直等到您调用 Save,然后在一个事务中完成它们。

此外,存储库不是工作单元,它更像是 UnitOfWork 的包装器。您的 UnitOfWork 跟踪模型中的所有实体,而不仅仅是单个实体。因此多个存储库可以共享一个 UnitOfWork。

于 2012-09-13T05:25:58.040 回答
1

UnitOfWork 模式用于管理 Model 对象的状态以及是否需要将其保存到数据库中。

考虑它的最佳方式是,如果您更改 Model 对象的属性,则该对象知道它已被更改(通常它被标记为脏),然后该对象由持久性机制处理。您可能在 IList 中有 10 个对象 - 您更改了其中的 2 个 - 当需要保存持久层时,知道只有 2 个已更改,并且只将它们保存到数据库中。

您可以在此处阅读有关其工作原理的更多信息

从事物的声音来看,您遇到的真正问题是如何创建持久层(您的存储库)。您需要的是某种形式的单一连接管理对象,它保存与数据库的连接,但以您程序集中的所有存储库都可以访问的方式进行。您需要的是一个单例对象,它可能是使用静态工厂模式创建的。

老实说,这是一段相当低级的数据访问代码,管理事务(已提交、正在处理等)和连接状态(打开、关闭)可能是一段麻烦的代码。如今,有许多框架,如 nHibernate、Entity Framework 和 Active Record,可以为您完成所有这些工作(具有讽刺意味的是,使用了您描述的许多模式)。

编辑:刚刚看到你的代码。如果你真的,真的想自己做,那么从你的 SQLHelper 类中删除 static 关键字,将连接代码移到名为 open 和 close 的单独方法中,并将 SQLHelper 类包装在一个总是返回单个实例的新静态工厂类中(辛格尔顿)。

于 2012-09-13T05:31:28.350 回答