tipos quien practico para lleno llenar llenado lading instrucciones hijo formato emite caso bill aduanas c# linq-to-sql nested datacontext transactionscope

c# - quien - ¿Cómo manejar el contexto de datos anidados en el BL?



quien emite el bl master y quien el bl hijo (4)

public class TestBL { public static void AddFolder(string folderName) { using (var ts = new TransactionScope()) { using (var dc = new TestDataContext()) { var folder = new Folder { FolderName = folderName }; dc.Folders.InsertOnSubmit(folder); dc.SubmitChanges(); AddFile("test1.xyz", folder.Id); AddFile("test2.xyz", folder.Id); AddFile("test3.xyz", folder.Id); dc.SubmitChanges(); } ts.Complete(); } } public static void AddFile(string filename, int folderId) { using (var dc = new TestDataContext()) { dc.Files.InsertOnSubmit( new File { Filename = filename, FolderId = folderId }); dc.SubmitChanges(); } } }

Este es un ejemplo de DataContext anidado (no probado). El problema comienza cuando se agrega un TransactionScope a nuestro pequeño experimento (como se muestra arriba). El primer AddFile en la función AddFolder escalará la transacción a DTC (lo cual es malo por todos los medios), porque AddFile inicializa el nuevo DataContext, abriendo así una segunda conexión al DB.

  1. ¿Cómo puedo usar DataContext anidado que no ocurrirá un uso de DTC?
  2. ¿Todo esto simplemente está mal? ¿Debo usar el DataContext de manera diferente?

He encontrado una forma de manejar tales situaciones.

Clase base de muestra para una entidad BL (la entidad heredará esta clase)

abstract public class TestControllerBase : IDisposable { public TestDataContext CurrentDataContext { get; private set; } protected TestControllerBase() { CurrentDataContext = new TestDataContext(); } protected TestControllerBase(TestDataContext dataContext) { CurrentDataContext = dataContext; } protected void ClearDataContext() { CurrentDataContext.Dispose(); CurrentDataContext = new TestDataContext(); } public void Dispose() { CurrentDataContext.Dispose(); } }

Controlador implementado

public sealed class BLTestController : TestControllerBase { public BLTestController() { } public BLTestController(TestDataContext dataContext) : base(dataContext) { } // The entity functions will be implemented here using CurrentDataContext }

Uso simple de un controlador implementado

var testController = new BLTestControllerA(); testController.DeleteById(1);

Uso más complejo de un controlador implementado (2 controladores en el mismo DataContext)

var testControllerA = new BLTestControllerA(); var testControllerB = new BLTestControllerB(testControllerA.CurrentDataContext); testControllerA.DeleteById(1); testControllerB.DeleteById(1);

Me gustaría ver más ideas sobre cómo resolver este enigma y comentarios sobre el código anterior.


No necesita hacer 2 o más viajes de ida y vuelta para esta transacción. Creo que LINQ-DataContext es inteligente para reconocer que esos archivos pertenecen al objeto de la carpeta e insertará primero la fila de la carpeta y los archivos después de eso (todo en el contexto de una transacción, por ej. BEGIN TRAN / COMMIT). Sin embargo, debes hacer lo siguiente:

dc.Files.InsertOnSubmit( new File { Filename = filename, Folder = folder });

en lugar de FolderId. Algo como esto:

public class TestBL { public static void AddFolder(string folderName) { using (var ts = new TransactionScope()) { using (var dc = new TestDataContext()) { var folder = new Folder { FolderName = folderName }; AddFile(dc, "test1.xyz", folder); AddFile(dc, "test2.xyz", folder); AddFile(dc, "test3.xyz", folder); dc.SubmitChanges(); } ts.Complete(); } } private static void AddFile(DataContext dc, string filename, Folder folder) { dc.Files.InsertOnSubmit( new File { Filename = filename, Folder = folder }); } public static void AddFile(string filename, int folderId) { using (var dc = new TestDataContext()) { var folder = new Folder { FolderId = folderId }; dc.Attach(folder, false); AddFile(dc, filename, folder); dc.SubmitChanges(); } } }

A su pregunta con respecto a DTC: no creo que sea posible evitar el DTC aquí debido a 2 conexiones abiertas. Creo que hicieron algunos cambios en esta área recientemente, ver aquí , pero el escenario descrito allí es un poco diferente (2 conexiones abiertas y cerradas una tras otra en lugar de 2 conexiones abiertas simultáneamente).


Además de pasar el DataContext a AddFiles como parámetro, también puede pasar un valor de Conexión de DataContext a otro DataContext. Eso garantizaría que el otro DataContext tenga la misma conexión.

Cada DataContext también tiene una propiedad de transacción, que probablemente podría establecer y transferir en lugar de usar el objeto TransactionScope.


Sin duda se debe evitar escalar a DTC cuando sea posible. Cuando leí por primera vez su pregunta, mi instinto me decía que su transacción no pasaría a DTC porque está utilizando la misma cadena de conexión en ambos contextos de datos. Sin embargo, según este artículo , estaba equivocado.

No estás solo en la confusión sobre las mejores prácticas con contextos de datos. Si buscas en la web para esto, hay respuestas en todo el mapa. En su ejemplo, puede pasar el contexto de datos al método AddFile. O bien, podría refactorizar este acceso a datos en una clase que mantenga la duración del contexto de datos hasta que la carpeta y los archivos estén todos guardados. Rick Strahl publicó un artículo sobre varias técnicas.

Aún así, ninguna de las respuestas que he visto en torno a LINQ to SQL parece muy satisfactoria. ¿Ha considerado evitar la gestión de su capa de datos mediante el uso de un ORM? He utilizado NetTiers con gran éxito, pero escuché cosas buenas sobre PLINQO . Ambos requieren CodeSmith , pero hay muchas alternativas .