arrière-plan
J'ai du code qui ouvre une connexion SQL, commence une transaction et effectue certaines opérations sur la base de données. Ce code crée un objet à partir de la base de données (dequeue), obtient des valeurs et le sauvegarde. L'ensemble de l'opération doit avoir lieu dans une transaction. Tout le code fonctionne parfaitement sans la transaction.
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
var transaction = connection.BeginTransaction();
try
{
var myObject = foo.Dequeue(connection, transaction);
var url = myObj.GetFilePathUri(connection, transaction);
//some other code that sets object values
myObj.SaveMessage(connection, transaction);
transaction.Commit(); //error here
}
catch(Exception ex)
{
transaction.Rollback();
//logging
}
finally
{
//cleanup code
}
}
retirer le code de la méthode
public foo Dequeue(SqlConnection connection, SqlTransaction transaction)
{
using (var command = new SqlCommand(DEQUEUE_SPROC, connection) {CommandType = CommandType.StoredProcedure, Transaction = transaction})
{
var reader = command.ExecuteReader();
if (reader.HasRows)
{
reader.Read();
ID = (Guid) reader["ID"];
Name = reader["Name"].ToString();
return this;
}
return null;
}
}
Obtenir le code de chemin
public string GetFilePathUri(SqlConnection connection, SqlTransaction transaction)
{
using (var command = new SqlCommand(FILEPATH_SPROC, connection) {CommandType = CommandType.StoredProcedure, Transaction = transaction})
{
var reader = command.ExecuteReader();
if (reader.HasRows)
{
reader.Read();
return reader["Path"].ToString();
}
return "";
}
}
Enregistrer le code
public void SaveMessage(SqlConnection connection, SqlTransaction transaction)
{
using (var command = new SqlCommand(SAVE_SPROC, connection) {CommandType = CommandType.StoredProcedure, Transaction = transaction})
{
command.Parameters.Add("@ID", SqlDbType.UniqueIdentifier).Value = ID;
command.Parameters.Add("@Name", SqlDbType.VarChar).Value = Name;
//other object params here
command.ExecuteNonQuery();
}
}
Le problème
Lorsque transaction.Commit () est appelée, j'obtiens l'erreur suivante:
L'opération de transaction ne peut pas être effectuée car des demandes en attente sont en cours de traitement sur cette transaction.
Qu'est-ce que je fais mal?
EDIT: Modification rapide pour dire que j'ai lu les autres questions sur ce problème sur SO, mais que je n'ai trouvé aucun lien avec ADO.net
J'ai déjà eu ce problème et le problème était que le lecteur devait être fermé. Essaye ça:
public foo Dequeue(SqlConnection connection, SqlTransaction transaction)
{
using (var command = new SqlCommand(DEQUEUE_SPROC, connection) {CommandType = CommandType.StoredProcedure, Transaction = transaction})
{
var reader = command.ExecuteReader();
if (reader.HasRows)
{
reader.Read();
ID = (Guid) reader["ID"];
Name = reader["Name"].ToString();
reader.Close();//Closing the reader
return this;
}
return null;
}
}
public string GetFilePathUri(SqlConnection connection, SqlTransaction transaction)
{
string filePathUri = "";
using (var command = new SqlCommand(FILEPATH_SPROC, connection) {CommandType = CommandType.StoredProcedure, Transaction = transaction})
{
var reader = command.ExecuteReader();
if (reader.HasRows)
{
reader.Read();
filePathUri = reader["Path"].ToString();
}
reader.Close();//Closing the reader
}
return filePathUri;
}
J'ai eu ce problème lorsque j'ai oublié d'utiliser wait sur une méthode asynchrone qui effectuait l'appel DB - la connexion était supprimée pendant l'exécution de la transaction car le programme n'attendait pas la fin de la requête avant d'essayer de tout supprimer.