只要涉及到数据库的操作,那么使用事务就是难免的。如果我们使用LINQ to SQL作为数据访问层,那么LINQ提供的SubmitChanges()方法自身就包含了对事务的处理。当然,我们也可以利用System.Data.Common.DbTransaction对事务进行处理,我们可以调用DataContext中Connection的方法BeginTransaction()启动事务,然后根据情况进行回滚或提交。例如是这样一段代码:
 
TransactionScope Troubleshooting_LINQ to SQLLinqSampleDataContext context = new LinqSampleDataContext();            
TransactionScope Troubleshooting_LINQ to SQLSystem.Data.Common.DbTransaction trans = null;
TransactionScope Troubleshooting_LINQ to SQLtry
TransactionScope Troubleshooting_LINQ to SQL_04{
TransactionScope Troubleshooting_LINQ to SQL_05   context.Connection.Open();
TransactionScope Troubleshooting_LINQ to SQL_05   trans = context.Connection.BeginTransaction();
TransactionScope Troubleshooting_LINQ to SQL_05   context.Transaction = trans;
TransactionScope Troubleshooting_LINQ to SQL_05
TransactionScope Troubleshooting_LINQ to SQL_05   context.Employees.InsertOnSubmit(emp);
TransactionScope Troubleshooting_LINQ to SQL_05                context.SubmitChanges();
TransactionScope Troubleshooting_LINQ to SQL_05
TransactionScope Troubleshooting_LINQ to SQL_05   trans.Commit();
TransactionScope Troubleshooting_LINQ to SQL_13}
TransactionScope Troubleshooting_LINQ to SQLcatch (Exception ex)
TransactionScope Troubleshooting_LINQ to SQL_04{
TransactionScope Troubleshooting_LINQ to SQL_05   if (trans != null)
TransactionScope Troubleshooting_LINQ to SQL_17   {
TransactionScope Troubleshooting_LINQ to SQL_05       trans.Rollback();
TransactionScope Troubleshooting_LINQ to SQL_19   }
TransactionScope Troubleshooting_LINQ to SQL_13}
 


然而,当我们在使用LINQ to SQL中时,往往会同时使用多个DataContext,此时我们就需要使用TransactionScope。TransactionScope Troubleshooting_LINQ to SQL        using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew))
TransactionScope Troubleshooting_LINQ to SQL_22        {
TransactionScope Troubleshooting_LINQ to SQL_05            try
TransactionScope Troubleshooting_LINQ to SQL_17            {
TransactionScope Troubleshooting_LINQ to SQL_05
TransactionScope Troubleshooting_LINQ to SQL_05                for (int i = 0; i < nominees.Count; ++i)
TransactionScope Troubleshooting_LINQ to SQL_17                {
TransactionScope Troubleshooting_LINQ to SQL_05                    Backup newBackup = nominees[i];
TransactionScope Troubleshooting_LINQ to SQL_05                    Ticket ticket = tickets[i];
TransactionScope Troubleshooting_LINQ to SQL_05
TransactionScope Troubleshooting_LINQ to SQL_05                    //update the information of ticket
TransactionScope Troubleshooting_LINQ to SQL_05                    //mainly add the information of employee;
TransactionScope Troubleshooting_LINQ to SQL_05                    ticket.EmployeeID = newBackup.EmployeeID;
TransactionScope Troubleshooting_LINQ to SQL_05                    ticket.HaveNominated = true;
TransactionScope Troubleshooting_LINQ to SQL_05                    ticket.IsConfirmedByManager = true;
TransactionScope Troubleshooting_LINQ to SQL_05                    ticket.Status = TicketStatus.Enroll.ToString();
TransactionScope Troubleshooting_LINQ to SQL_05
TransactionScope Troubleshooting_LINQ to SQL_05                    ticketAccessor.Update(ticket);
TransactionScope Troubleshooting_LINQ to SQL_19                }
TransactionScope Troubleshooting_LINQ to SQL_05
TransactionScope Troubleshooting_LINQ to SQL_05                //update the IsSubmit of backup;
TransactionScope Troubleshooting_LINQ to SQL_05                ChangeSubmitStatue(backup);
TransactionScope Troubleshooting_LINQ to SQL_05
TransactionScope Troubleshooting_LINQ to SQL_05                //remove the record of nominee in backup table
TransactionScope Troubleshooting_LINQ to SQL_05                Delete(nominees);
TransactionScope Troubleshooting_LINQ to SQL_19            }
TransactionScope Troubleshooting_LINQ to SQL_05            catch (Exception ex)
TransactionScope Troubleshooting_LINQ to SQL_17            {
TransactionScope Troubleshooting_LINQ to SQL_05                ThrowHelper.ThrowBackupException("Finalizing occurs an error. The transcation will be rollback.");
TransactionScope Troubleshooting_LINQ to SQL_05                return false;
TransactionScope Troubleshooting_LINQ to SQL_19            }
TransactionScope Troubleshooting_LINQ to SQL_05
TransactionScope Troubleshooting_LINQ to SQL_05            scope.Complete();
TransactionScope Troubleshooting_LINQ to SQL_13        }

代码中,分别涉及到Update, Delete等操作,因此我们势必需要用事务,保证数据整体提交或整体回滚。在使用事务的时候,有一些前置条件是必备的。例如启动Distributed Transaction Coordinator服务,否则,就会抛出System.Data.SqlClient.SqlException异常,信息为:"MSDTC on server '{Server Name}' is unavailable."。是的,很多资料都是这样描述的。然而,现实并没有这么简单。我们首先得考虑运行代码的机器是否与数据库所在的机器是同一台。这里所谓的启动Distributed Transaction Coordinator服务,实际上是要启动数据库服务器的服务。如果数据库与代码服务器是同一台,通过这样的设置就没有错误了。

当数据库与代码服务器分属两台机器呢?同样运行如上的代码,就会抛出System.Transactions.TransactionManagerCommunicationException异常。异常信息为:"Network access for Distributed Transaction Manager (MSDTC) has been disabled. Please enable DTC for network access in the security configuration for MSDTC using the Component Services Administrative tool."

这是一种通信错误,原因在于两台服务器之间的安全配置禁止了分布式事务。解决办法是在运行代码的服务器上,配置Component Services。方法如下:
1、在Run运行窗口中,输入dcomcnfg命令,这样就可以打开Component Services。
2、选择Component Services->Computers->My Computer;
3、右键单击My Computer,在弹出的快捷菜单中,选择“Properties”,然后点击MSDTC tab;
4、在MSDTC tab中,点击Security Configuration按钮;
5、在弹出的对话框中参照下表的建议进行设置:
Configuration Option Default Value Recommended Value

Network DTC Access

Disabled

Enabled

Client and Administration

 

 

Allow Remote Clients

Disabled

Disabled

Allow Remote Administration

Disabled

Disabled

Transaction Manager Communication

 

 

Allow Inbound

Disabled

Enabled

Allow Outbound

Disabled

Enabled

Mutual Authentication Required

Enabled

Enabled if all remote machines are running Win2K3 SP1 or XP SP2 or higher, and are configured with “Mutual Authentication Required”.

Incoming Caller Authentication Required

Disabled

Enabled if running MSDTC on cluster.

No Authentication Required

Disabled

Enabled if remote machines are pre-Windows Server 2003 SP1 or pre- Windows XP SP2.

Enable TIP

Disabled

Enabled if running the BAM Portal.

Enable XA Transactions

Disabled

Enabled if communicating with an XA based transactional system such as when communicating with IBM WebSphere MQ using the MQSeries adapter.

最后的设置如截图:
securityconfig.gif
如果操作系统是Windows 2003,通常默认的设置就是正确的。不过我们在编写程序时,不管是Unit Test,还是其他测试,最频繁的还是在本机上运行。如果操作系统是Windows XP,就不得不进行这样的设置了。