Sto cercando di evitare l'escalation MSDTC nella mia applicazione. Sto usando LINQ con SQL Server Express 2008 R2 e in seguito utilizzerò la versione completa.Nested TransactionScope e/o connessioni nidificate che provocano l'escalation MSDTC
Ho scritto una classe wrapper del database che crea le connessioni necessarie e le elimina il più rapidamente possibile. La stringa di connessione rimane la stessa su tutte le connessioni.
Ecco una versione molto più sintetica della mia classe:
public class SqlServerDatabaseWrapper {
public SqlServerDatabaseWrapper(string connectionString) {
ConnectionString = connectionString;
}
public string ConnectionString { get; private set; }
private static IDbConnection GetOpenConnection() {
var conn = new SqlConnection(ConnectionString);
conn.Open();
return conn;
}
// there is also a second method to return a value
// there is PerformCommandAction for SqlCommand as well
public void PerformDataContextAction<TContext>(Func<IDbConnection, TContext> creator, Action<TContext> action) where TContext : DataContext {
PerformConnectionAction(conn => {
using (var context = creator(conn))
action(context);
});
}
// there is also a second method to return a value
public void PerformConnectionAction(Action<IDbConnection> action) {
using (IDbConnection conn = GetOpenConnection(ConnectionString)) {
action(conn);
}
}
}
utilizzati come segue:
var db = new SqlServerDatabaseWrapper(connectionString);
db.PerformDataContextAction(
conn => new SomeDataContext(conn),
context => { /* do something */ }
);
Se metto un blocco intorno al contenuto del metodo PerformConnectionAction, in modo che solo una può essere eseguito in un momento, quindi tutto funziona ma c'è una penalità di prestazioni notevole. Tuttavia, quando lo rimuovo, si intensifica.
Il codice che utilizza il wrapper utilizza TransactionScope e potrebbe essere nidificato TransactionScopes e/o chiamate a PerformDataContextAction o PerformConnectionAction (che creano ciascuna una nuova connessione con la stessa stringa di connessione); in pseudo-codice (poiché potrebbe verificarsi tra diversi classi/metodi):
var db = new SqlServerDatabaseWrapper(connectionString)
using (TransactionScope tran = new TransactionScope()) {
db.PerformDataContextAction(
/* ... */,
context => {
using (TransactionScope tran2 = new TransactionScope()) {
db.PerformConnectionAction(conn => { /* some stuff */ });
tran2.Complete();
}
}
tran.Complete();
}
noti anche che non v'è l'uso dei metodi Membership statici che potrebbero verificarsi in vari punti.
Vorrei anche aggiungere che la stringa di connessione è la seguente:
Data Source=.\SQLEXPRESS;Initial Catalog=db1;User Id=test1;Password=test1;MultipleActiveResultSets=true;Enlist=false;
La domanda è: come faccio a refactoring/riscrivere il mio codice in modo che la mia applicazione in grado di eseguire bene, senza MSDTC, e senza serrature introducendo ?
Grazie
Quale versione di SQL Server si sta utilizzando? – Oded
SQL Express 2008 R2, in seguito essere immesso nella versione completa – enashnash
Sono un po 'sconcertato che l'aggiunta di un blocco impedisce l'escalation, poiché 'TransactionScope' sono legati al thread e i blocchi influiscono solo sull'interazione dei thread, ma non sull'ordine di operazioni all'interno di un thread, a meno che il threading non introduca un comportamento non deterministico, in cui potrei vedere come le serrature cambiano le cose. Se sei ancora interessato a una risposta, ti preghiamo di farci sapere di più su ciò che accade sul thread-wise. –