2017-10-05 1 views
0

J'ai un lot de lignes qui doivent être insérées dans une seule transaction, la première ligne est un en-tête et toutes les lignes suivantes doivent faire référence au premier.Insérer des lignes dans la transaction avec FK à la première ligne créée

Voici comment je tente d'insérer la première ligne:

using (var connection = new SqlConnection(_connectionString)) 
{ 
    connection.Open(); 
    var transaction = connection.BeginTransaction(); 

    try 
    { 
     // create the record header 
     using (var createRecordCommand = connection.CreateCommand()) 
     { 
      createRecordCommand.CommandText = 
       "DECLARE @RecordId INT;" + 
       $"INSERT INTO ..." + 
       "SET @RecordId = scope_identity();"; 

      createRecordCommand.Transaction = transaction; 
      createRecordCommand.ExecuteNonQuery(); 

Je me bats pour faire référence à RECORDID dans les déclarations ultérieures, il semble penser n'est pas déclaré la @RecordId variable dans l'extrait ci-dessous . 'Doit déclarer la variable scalaire "@RecordId".'

using (var createAttributeCommand = connection.CreateCommand()) 
{ 
    createAttributeCommand.Transaction = transaction; 

    createAttributeCommand.CommandText = 
     $"INSERT INTO ... (RecordId,...) VALUES (@RecordId,...)"; 

extraire également la variable @RecordId comme paramètre se révèle difficile, il n'aime pas ça quand j'utiliser la ligne ci-dessous conjointement avec DECLARE @RecordId INT;

createRecordCommand.Parameters.Add(new SqlParameter("@RecordId", SqlDbType.Int) { Direction = ParameterDirection.Output }); 
+1

Pourquoi ne pas mettre votre logique dans une procédure stockée et puis juste appeler la procédure à partir de C#? –

+0

J'ai rasé la complexité de la question hors de la question, ce que nous essayons de réaliser est trop complexe pour un proc stocké malheureusement. –

+1

Ummm quoi? Trop complexe pour une procédure stockée? Effectuez l'insertion en tant que procédure stockée et utilisez un paramètre OUTPUT pour renvoyer l'identité. –

Répondre

0

Je ne vous avais pas réalisé peut extraire des données avant la validation de la transaction, en supposant que, puisque ExecuteScalar() ne fonctionnait pas, je rencontrerais le même problème.

Comme souligné dans les commentaires, une procédure stockée est probablement la meilleure solution, les experts SQL sonnent comme des disques cassés après un certain temps, p. Ce sera trop complexe à court terme car il y a un nombre variable de paramètres, la validation et les valeurs vont muter en fonction de la logique métier. En tant qu'équipe, nous sommes plus à l'aise en C#, donc c'est là que la logique restera jusqu'à ce qu'elle soit complètement clouée.

Le code résultant est le suivant, N.B. en code réel, passer toutes les variables en tant que paramètres pour éviter l'injection SQL, nous sommes, c'est la démonstration que:

using (var connection = new SqlConnection(_connectionString)) 
{ 
    connection.Open(); 
    var transaction = connection.BeginTransaction(); 

    try 
    { 
     // create the record header 
     using (var createRecordCommand = connection.CreateCommand()) 
     { 
      createRecordCommand.CommandText = 
       //"DECLARE @RecordId INT;" + 
       $"INSERT INTO ..." + 
       "SET @RecordId = scope_identity();"; 

      createRecordCommand.Transaction = transaction; 
      createRecordCommand.Parameters.Add(new SqlParameter("@RecordId", SqlDbType.Int) { Direction = ParameterDirection.Output }); 
      createRecordCommand.ExecuteNonQuery(); 

      recordId = (int) createRecordCommand.Parameters["@RecordId"].Value; 

// ... 

using (var createAttributeCommand = connection.CreateCommand()) 
{ 
    createAttributeCommand.Transaction = transaction; 
    createAttributeCommand.CommandText = 
     $"INSERT INTO ... (RecordId,...) VALUES ({recordId},...)"; 

// ... 

transaction.Commit();