C# et transaction SQL : Comportement inattendu
Bonjour,
J'ai un traitement dans une boucle qui fait :
- Une insertion
- Une selection sur les données insérées
Etant donné que je peux avoir pas mal d'itérations dans ma boucle, j'utilise deux objets SqlCommand différents, afin de ne pas devoir recréer mes paramètres à chaque itération inutilement.
J'ai besoin d'une transaction qui porte sur l'ensemble de la boucle.
J'ai donc procédé comme suit :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
|
using (SqlConnection cnx = new SqlConnection(@"Server=.\SQLEXPRESS;Database=MagicGED;Trusted_Connection=True;"))
{
cnx.Open();
using (SqlTransaction trans = cnx.BeginTransaction())
{
using (SqlCommand cmdIns = cnx.CreateCommand())
{
cmdIns.Transaction = trans;
cmdIns.CommandText = "insert into document (id, title, extension, doc) output inserted.id values (default, @title, @extension, 0x0)";
SqlParameter pTitle = cmdIns.CreateParameter();
pTitle.ParameterName = "title";
pTitle.SqlDbType = SqlDbType.NVarChar;
pTitle.Size = 256;
cmdIns.Parameters.Add(pTitle);
SqlParameter pExtension = cmdIns.CreateParameter();
pExtension.ParameterName = "extension";
pExtension.SqlDbType = SqlDbType.NVarChar;
pExtension.Size = 10;
cmdIns.Parameters.Add(pExtension);
using (SqlCommand cmdSel = cnx.CreateCommand())
{
cmdSel.Transaction = trans;
cmdSel.CommandText = "select doc.PathName(), GET_FILESTREAM_TRANSACTION_CONTEXT() from document where id = @id";
SqlParameter pId = cmdSel.CreateParameter();
pId.ParameterName = "id";
pId.SqlDbType = SqlDbType.UniqueIdentifier;
cmdSel.Parameters.Add(pId);
DirectoryInfo di = new DirectoryInfo(fbd.SelectedPath);
FileInfo[] files = di.GetFiles("*.*", SearchOption.AllDirectories);
toolStripProgressBar1.Value = 0;
toolStripProgressBar1.Minimum = 0;
toolStripProgressBar1.Maximum = files.Length;
toolStripProgressBar1.Visible = true;
foreach (FileInfo fsi in files)
{
bool ignore = true;
for (int i = 0, len = ACCEPT_EXTENSIONS.Length; i < len; i++)
{
if (ACCEPT_EXTENSIONS[i] == fsi.Extension.ToLower())
{
ignore = false;
break;
}
}
if (!ignore)
{
pTitle.Value = fsi.Name;
pExtension.Value = fsi.Extension.ToLower();
pId.Value = cmdIns.ExecuteScalar();
using (SqlDataReader dr = cmdSel.ExecuteReader(CommandBehavior.SingleResult | CommandBehavior.SingleRow | CommandBehavior.SequentialAccess))
{
string path = dr.GetString(0);
byte[] tc = dr.GetSqlBytes(1).Buffer;
byte[] b = new byte[1048576];
using (SqlFileStream sfs = new SqlFileStream(path, tc, FileAccess.Write, FileOptions.SequentialScan, 0))
{
using (FileStream fs = new FileStream(fsi.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
int i = 0, l = 0;
while ((l = fs.Read(b, 0, b.Length)) > 0)
{
sfs.Write(b, 0, l);
i += l;
}
fs.Close();
}
sfs.Close();
}
}
}
toolStripProgressBar1.Value++;
statusStrip1.Refresh();
}
}
}
trans.Commit();
}
cnx.Close();
} |
J'affecte ma transaction à mes deux SqlCommand.
Et là, c'est le drame : l'insertion passe, mais impossible de relire la donnée lue avec le second SqlCommand.
Suis-je obligé d'utiliser un seul objet SqlCommand ?
J'utilise pourtant le même SqlTransaction pour les deux SqlCommand.
Comment faire ? J'ai tenté différents modes d'isolation de transaction, mais aucun ne semble résoudre le problème. De plus, je ne voudrais pas non plus faire n'importe quoi dans ma transaction...