2012-09-13 38 views
1

我一直在阅读有关UnitOfWork模式的最近两天,但没有正确理解它。IUnitOfWork会适合我的场景

我有每个类的存储库。 例如。 员工,出勤,薪资,部门,地址等。

存储库方式 - 这些类中的每一个都会有自己的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中使用存储过程吗?

+0

我没有看到ORM与更改需求有什么关系。如果你的意思是你的数据模型会经常变化,那么你需要改变它..所以ORM或DAL无关紧要。 –

+0

@MystereMan:是的,我的数据模型会经常变化,以及我正在为应用程序开发采用渐进式方法。在这个级别不知道需求。 –

+0

同样,无论您是否使用ORM,您都必须更改您的代码,因此我没有看到任何差异或任何理由担心使用ORM。很多人使用ORM进行迭代开发。 –

回答

2

你有一些非常错误的假设。首先,仅仅因为你有两个存储库,如果你使用它们,并不意味着你有两个数据库连接。数据库连接由大多数ORM(例如实体框架和nHibernate)汇集。所以你不知道如何处理连接,但通常可以确定的是,当你调用SaveChanges时,它会有一个隐含的事务并作为一个单独的原子动作出现。其次,你忽略了ORM的一个关键好处,那就是导航属性和集合。如果你有一个Employee表,那么它应该有一个Address导航属性或者地址集合。

因此,假设你想插入一个新员工。您创建一个新的员工实体,然后创建一个新的地址实体,然后将该地址添加到员工,然后将该员工添加到您的ORM。当您调用Commit或SaveChanges或任何导致您的ORM更新的内容时,它会更新两个实体,并将其作为单个事务处理。

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

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

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

编辑:根据您的编辑

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

要记住UnitOfWork的重要之处在于它是一种实体缓存。您向其中添加或更新脏实体,并且它不会逐个保存它们,而是一直等到您调用Save,然后在单个事务中完成它们。

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

+0

@ShantanuGupta - 在那里有一百万个存储库实现,以及一百万种不同的实现方式。我不能告诉你应该如何编写它,因为我不知道你的需求,或者你的数据模型,或其他任何东西。但是,问题不是交易对象,而是一般情况下如何构建数据访问。 –

1

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

想想最好的方法是如果你改变你的模型对象的属性,然后对象知道它已被改变(通常它被标记为脏),然后这个对象是由持久性机制处理。您可能在IList中有10个对象 - 您更改其中2个 - 当保存持久层的时间知道只有2个已更改并仅将其保存到数据库中。

你可以阅读更多的关于如何工作here

通过对事物的声音,你有真正的问题是你如何创造你的持久层(版本库)。您需要的是某种形式的单连接管理对象,它可以保持与数据库的连接,但是可以通过组装中的所有存储库访问。你需要的是一个Singleton对象,可能是使用静态工厂模式创建的。

现在说实话,这是一个相当低级的数据访问代码和管理事务(提交,在事务等)和连接状态(打开,关闭)可能是一个麻烦的代码。现在有很多像nHibernate,Entity Framework和Active Record这样的框架为你做了所有这些工作(讽刺地使用你描述的许多模式)。

编辑:刚才看到你的代码。如果你真的想自己做,那么从SQLHelper类中移除static关键字,将连接代码移出到单独的方法中,称为open和close,然后将SQLHelper类包装在一个新的静态Factory类中,该类始终返回一个单一实例辛格尔顿)。

+0

感谢您的回复。我从来没有在任何ORM上工作过,所以有点犹豫。我已经阅读过关于EF的文章,并且很少担心在经常变化的需求上会对代码产生什么影响。如何使用它与WCF服务。设计一个实体对我来说也是一个挑战 –

+0

我阅读了关于EF的映射方案,但我仍然不清楚这些http://msdn.microsoft.com/en-us/library/cc716779.aspx这些使我决定不要去EF –

+0

我使用nHibernate作为我的ORM和Castle Windsor作为IoC容器(它可以管理像Singletons这样的事情)。如果你想看看这种架构在行动,那么我会建议看看夏普体系结构。你可能不会使用它,但很高兴看到其他人是如何做到这一点的。 –