2009-04-16 14 views
64

Tengo un fragmento de código que implica varias inserciones pero necesito ejecutar el método de enviar cambios antes de terminar de insertar en otras tablas para poder adquirir una Id. He estado buscando a través de Internet y no he podido encontrar cómo crear una transacción en linq a sql. He puesto comentarios en el código donde quiero que se realice la transacción.¿Cómo crear una transacción LINQ to SQL?

var created = false; 
    try 
    { 
     var newCharacter = new Character(); 
     newCharacter.characterName = chracterName; 
     newCharacter.characterLevel = 1; 
     newCharacter.characterExperience = 0; 
     newCharacter.userUsername = userUsername; 
     newCharacter.characterClassID = ccslst[0].characterClassID; 
     //Open transaction 


      ydc.Characters.InsertOnSubmit(newCharacter); 
      ydc.SubmitChanges(); 

      foreach (var ccs in ccslst) 
      { 
       var cs = new CharacterStat(); 
       cs.statId = ccs.statID;       
       cs.statValue = ccs.statValue; 
       cs.characterID = newCharacter.characterID; 
       ydc.CharacterStats.InsertOnSubmit(cs); 
      }      


      var ccblst = ydc.ClassBodies.Where(cb => cb.characterClassID == newCharacter.characterClassID); 
      foreach (var ccb in ccblst) 
      { 
       var charBody = new CharacterBody(); 
       charBody.bodyId = ccb.bodyId; 
       charBody.bodyPartId = ccb.bodyPartId; 
       charBody.characterID = newCharacter.characterID; 
       ydc.CharacterBodies.InsertOnSubmit(charBody); 
      } 
      ydc.SubmitChanges();  
      created = true; 
     //Commit transaction 
     } 
     catch (Exception ex) 
     { 
      created = false; 
      //transaction Rollback;      
     } 
     return created; 

EDIT: He olvidado mencionar que ydc es mi DataContext

Respuesta

65

Wrap todo el asunto en un TransactionScope. Llame al transaction.Complete() en el punto donde desea comprometerse. Si el código sale del bloque sin llamar al Complete(), la transacción se revertirá. Sin embargo, después de mirar la respuesta de @s_ruchit y volver a examinar su código, probablemente podría volver a escribir esto para no requerir un TransactionScope. El primer ejemplo usa el TransactionScope con su código tal como está. El segundo ejemplo realiza algunos cambios menores, pero logra el mismo propósito.

Un lugar donde necesitaría usar el TransactionScope es cuando está leyendo un valor de la base de datos y usándolo para establecer un nuevo valor en un objeto que se agrega. En este caso, la transacción LINQ no cubrirá la primera lectura, solo la posterior presentación del nuevo valor. Dado que está utilizando el valor de la lectura para calcular un nuevo valor para la escritura, necesita que la lectura esté envuelta en la misma transacción para garantizar que otro lector no calcule el mismo valor y obvie su cambio. En su caso, solo realiza escrituras para que la transacción LINQ estándar funcione.

Ejemplo 1:

var created = false; 

using (var transaction = new TransactionScope()) 
{ 
    try 
    { 
     var newCharacter = new Character(); 
     newCharacter.characterName = chracterName; 
     newCharacter.characterLevel = 1; 
     newCharacter.characterExperience = 0; 
     newCharacter.userUsername = userUsername; 
     newCharacter.characterClassID = ccslst[0].characterClassID; 

     ydc.Characters.InsertOnSubmit(newCharacter); 
     ydc.SubmitChanges(); 

     foreach (var ccs in ccslst) 
     { 
      var cs = new CharacterStat(); 
      cs.statId = ccs.statID;       
      cs.statValue = ccs.statValue; 
      cs.characterID = newCharacter.characterID; 
      ydc.CharacterStats.InsertOnSubmit(cs); 
     }      

     var ccblst = ydc.ClassBodies.Where(cb => cb.characterClassID == newCharacter.characterClassID); 
     foreach (var ccb in ccblst) 
     { 
      var charBody = new CharacterBody(); 
      charBody.bodyId = ccb.bodyId; 
      charBody.bodyPartId = ccb.bodyPartId; 
      charBody.characterID = newCharacter.characterID; 
      ydc.CharacterBodies.InsertOnSubmit(charBody); 
     } 
     ydc.SubmitChanges();  
     created = true; 

     transaction.Complete(); 
    } 
    catch (Exception ex) 
    { 
     created = false; 
    } 
} 
return created; 

Ejemplo 2:

try 
    { 
     var newCharacter = new Character(); 
     newCharacter.characterName = chracterName; 
     newCharacter.characterLevel = 1; 
     newCharacter.characterExperience = 0; 
     newCharacter.userUsername = userUsername; 
     newCharacter.characterClassID = ccslst[0].characterClassID; 

     ydc.Characters.InsertOnSubmit(newCharacter); 

     foreach (var ccs in ccslst) 
     { 
      var cs = new CharacterStat(); 
      cs.statId = ccs.statID;       
      cs.statValue = ccs.statValue; 
      newCharacter.CharacterStats.Add(cs); 
     }      

     var ccblst = ydc.ClassBodies.Where(cb => cb.characterClassID == newCharacter.characterClassID); 
     foreach (var ccb in ccblst) 
     { 
      var charBody = new CharacterBody(); 
      charBody.bodyId = ccb.bodyId; 
      charBody.bodyPartId = ccb.bodyPartId; 
      newCharacter.CharacterBodies.Add(charBody); 
     } 
     ydc.SubmitChanges();  
     created = true; 
    } 
    catch (Exception ex) 
    { 
     created = false; 
    } 
+0

No está seguro acerca de la sintaxis, no he puesto mi código en este ámbito: el uso de (TransactionScope ts = new TransactionScope()) { // mi código } – Drahcir

+0

Lo agregué a su código y pegué como un ejemplo. – tvanfosson

+0

Funcionó, gracias – Drahcir

38

No es necesario hacer explícita Implementación de transacciones durante el uso de LINQ a SQL. Todas las operaciones DB están envueltas en una transacción por defecto.

Ex:

AppDataContext db = new AppDataContext(); 

<In memory operation 1 on db> 
<In memory operation 2 on db> 
<In memory operation 3 on db> 
<In memory operation 4 on db> 

db.SubmitChanges(); 

Todas las operaciones entre db inicialización DataContext y db.SubmitChanges() se envuelven alrededor de una base de datos de transacciones por .Net asegurar su base de datos para estar en consonancia con integridad y propiedad mantenida a través de tablas.

leí un artículo de Scott Guthriehere: - http://weblogs.asp.net/scottgu/archive/2007/07/11/linq-to-sql-part-4-updating-our-database.aspx

+0

Pero necesitaba una ID que se generó en los primeros cambios de envío, no sabía lo contrario cómo adquirir el ID. – Drahcir

+3

Visita el artículo escrito por ScottGu. Puedes asociar sin la ID. Esa es la belleza de LINQ-to-SQL. Si no estás haciendo esto, no estás aprovechando el Linq-To-Sql. Te recomiendo que leas el artículo de ScottGu. Puedes encontrar el enlace en mi respuesta. –

+0

Sí. Parece que podría reescribir esto para no requerir una transacción externa. Actualizaré mi respuesta. – tvanfosson