0
votes

We are doing an import process from a source database to a destination database. We need to run these imports frequently in an automated fashion.

The source is on a separate server than the destination. Both are MS SQL 2008. We access the source using Linq2SQL and the destination using a custom Data Layer. We do not ever modify the source DB (though we do not restore it as read-only at present). However, right now when we run the import within a transactionScope, the entire transaction gets promoted to DTC because we access two DBs on separate servers.

If we were to make the source DB read-only, would it still do this?

Any other suggestions on how to avoid the DTC promotion in this scenario?

Follow-up questions to Remus' answer (thanks again):

Follow-up #1: My import routine is structured such that it imports records from the source and creates new records in the destination. Like this:

using(var scope = new TransactionScope())
{
   // read some from source db using Linq2Sql
   // transform source info
   // update destination

   // read some more from source db using Linq2Sql
   // transform source info
   // update destination

}

Are you saying to surround the Linq2Sql bits in a TransactionScope with RequiresNew? Or, I guess, sine I really do not care about transactions at the source, I could surround with TransactionScope with Suppress to that connection's inclusion in any transaction at all, right?

Follow-up #2:

When you say "open a second connection, even to the same Database" - I have read several variations on this:

  1. "second connection" == second instance of the Connection object even it exactly the same connectionstring
  2. "second connection" == connection to a separate Resource Manager and on SQL2005 and before this means same as 1 above, but on SQL2008 this means a separate instance (i.e. two DBs on the same instance do not get promoted)
1

1 Answers

2
votes

The moment you open a second ADO.Net connection inside a transaction scope, both connections will be promoted to DTC. even if is a new connection to the same DB, doesn't matter. Database read-onlyness has also nothing to do with it, and couldn't possible have anything to do with it. First, connections are not database specific since they can change the database after openning. Second, a read only database can do plenty of writes (e.g. can invoke readonlydb.dbo.myProcedure and inside the procedure I can update writabledb.dbo.table).

If you want to avoid the DTC then you must use different transaction scopes between the two access layers (ie. create a new scope with RequireNew).

Update

If is possible to do the reads outside of the scope it would be perfect:

// read some from source db using Linq2Sql 
// read some more from source db using Linq2Sql 
using(var scope = new TransactionScope()) 
{ 
   // transform source info 
   // update destination 

   // transform source info 
   // update destination 
} 

I understand this is higly unlikely though, as probably the second set of reads is dependent o the result of first transform/update usually. So you would best supress the scope when doing the read:

using(var scope = new TransactionScope()) 
{ 
   using(var nada= new TransactionScope(TransactionScopeOption.Supress))
   {
       // read some from source db using Linq2Sql 
       // transform source info 
   }
   // update destination 

   using(var nada= new TransactionScope(TransactionScopeOption.Supress))
   {
       // read some more from source db using Linq2Sql
       // transform source info 
   } 
   // update destination 
} 

BTW I assume that 'read some data using linq' means u actually enumerate the query, don't just create the query expression and use the expression later. I don't know exactly how a transaction scope interacts with a query expression, but my assumption is that the scope applies to the query execution, not the declaration.