J'importe un fichier plat de factures dans une base de données à l'aide de C #. J'utilise les transactionsCope pour rétrécir la totalité de l'opération si un problème est rencontré. P>
Il s'agit d'un fichier d'entrée délicat, dans une ligne d'une seule ligne n'est pas nécessaire un enregistrement égal. Il comprend également des enregistrements liés. Une facture aurait une ligne d'en-tête, des articles de ligne, puis une ligne totale. Certaines des factures devront être ignorées, mais je ne sais peut-être pas que cela doit être ignoré avant d'atteindre la ligne totale. p>
Une stratégie consiste à stocker l'en-tête, les éléments de la ligne et la ligne totale en mémoire et tout enregistrer une fois que la ligne totale est atteinte. Je poursuis cela maintenant. p>
Cependant, je me demandais si cela pouvait être fait d'une manière différente. Création d'une transaction «imbriquée» autour de la facture, insérant la ligne d'en-tête et des éléments de ligne, puis mettez à jour la facture lorsque la ligne totale est atteinte. Cette transaction "imbriquée" reviendrait si elle est déterminée que la facture doit être ignorée, mais la transaction globale continuerait. P>
est-ce possible, pratique et comment allez-vous configurer cela? p>
5 Réponses :
Au lieu d'utiliser des transactions imbriquées, vous pouvez créer une transaction par facture. De cette façon, seules les mises à jour réussies de factures entières se produiront. P>
Si vous nuez les transactions comme vous le décrivez, vous risquez d'avoir le jeu de données entier à rouler, ce qui n'est pas ce que vous voulez. P>
Je veux que tout retourna s'il y a un problème.
Personnellement, je verrais d'abord si la facture doit être ajoutée - si elle le fait, alors faites vos insertions (dans une transaction). Sinon, passez simplement à la prochaine facture. p>
Je ne pense pas que ce soit bien d'insérer et ensuite faire un retour dans la façon dont vous décrivez. P>
+1 pour la solution de Kiss. Je traiterais d'abord l'intégralité du fichier dans une zone de transfert (en mémoire, ou s'il est énorme une table d'intermédiaire de la base de données), puis enregistrez les données valides sur la table principale.
Jusqu'à présent, tenant la facture actuelle et l'élément de ligne associé en mémoire fonctionne. J'utilise Linq2SQL pour les stocker pour que je n'ai pas besoin d'écrire beaucoup de SQL pour traiter le graphique d'objet. Une fois qu'il détermine, la facture doit être enregistrée, elle soumet et dispose du contexte de données.
Une transaction interne défaillante réduirait la transaction extérieure, de sorte que vous ne pouvez pas aller à cet itinéraire. p>
Vous pouvez probablement le simuler, cependant, en utilisant une table TEM (ou une charge). Insérez chaque facture de manière transactionnelle dans la table de chargement, puis passez de la table de chargement à une table permanente atomique. P>
ni le Vous pouvez nier Pour expliquer plus en détail, considérez les éléments suivants: P> Vous pouvez donc espérons que rien de ces options ne sont réellement imbriquées et ne vous donnera pas ce que vous voulez. L'option La chose la plus proche que vous puissiez obtenir Pour les transactions tristes imbriquées dans SQL Server est l'instruction Sinon, vous devrez utiliser des transactions distinctes pour chaque facture selon la suggestion de ODED. P> transactionsCope code> NOR SQL Server supporte les transactions imbriquées. transactionsCOPE code> des instances, mais cela n'a que l'apparence sortante d'une transaction imbriquée. En réalité, il y a quelque chose d'appelé une transaction "ambiante", et il ne peut y en avoir qu'un à la fois. Quelle transaction est la transaction ambiante dépend de ce que vous utilisez pour transactionsCOPOPtion code> lorsque vous créez la portée. P> using (var outer = new TransactionScope())
{
DoOuterWork();
using (var inner1 = new TransactionScope(TransactionScopeOption.Suppress))
{
DoWork1();
inner1.Complete();
}
using (var inner2 = new TransactionScope(TransactionScopeOption.RequiresNew))
{
DoWork2();
inner2.Complete();
}
using (var inner3 = new TransactionScope(TransactionScopeOption.Required))
{
DoWork3();
inner3.Complete();
}
outer.Complete();
}
inner1 code> est exécuté dans une transaction implicite, indépendamment de externe code>. Rien qui arrive dans dowork1 code> est garanti d'être atomique. Si cela échoue à mi-chemin, vous aurez des données incohérentes. Tout travail qui se produit ici est toujours engagé, peu importe ce qui arrive à externe code>. P> li>
inner2 code> est exécuté dans une nouvelle transaction, indépendamment de externe code>. Ceci est une transaction em> différente externe code> mais c'est externe code> ( dooreterwork () code>) et l'un des autres étendues peuvent toujours être commis, mais voici le rub: inner2 code>. strong> C'est pourquoi il n'est pas véritablement imbriqué. En outre, inner2 code> n'aura pas accès à des lignes verrouillées par externe code>, afin que vous puissiez vous retrouver avec des blocages ici si vous n'êtes pas prudent. P> li>
inner3 code> est exécuté dans la transaction extérieur code>. Ceci est le comportement par défaut. Si dowork3 () code> échoue et inner3 code> ne finit jamais, l'ensemble de la transaction code> externe code> est renvoyé. De même, si inner3 code> est terminé avec succès, mais externe code> est renvoyé, puis tout travail effectué dans dowork3 () code> est également roulé. P> li>
ul> requise code> se rapproche d'une transaction imbriquée, mais ne vous donne pas la possibilité de commiser ou de rouler indépendamment des unités de travail spécifiques à l'intérieur de la transaction. P> SAVE TRAN CODE> COMMUNAIRE avec certains Essayez / attrayez les blocs CODE>. Si vous pouvez mettre votre logique à l'intérieur d'une ou plusieurs procédures stockées, ce serait une bonne option. P>
Merci pour les détails. Cela n'était pas clair dans la documentation MSDN.
+1 pour une explication très excellente et très approfondie. Bien fait, monsieur.
+1 Tout comme @Remi - très belle explication, et cela a aidé à me sauver ce soir. J'aimerais pouvoir + plus encore! Merci!
Ceci est accompli avec un Point de sauvegarde de transaction . Il ressemble généralement à quelque chose comme ceci: J'ai utilisé un pseudo pseudo basé sur des transact-sql et ce n'est pas un accident. Les points de sauvegarde sont un concept de base de données et les transactions .NET ne les supportent pas. Vous pouvez utiliser SQLTransaction directement et exploiter SQLTransAction.save ou vous pouvez utiliser des procédures stockées T-SQL modélisées après un Modèle de sécurité d'exception . Je vous recommanderais d'éviter les transactions .NET (c.-à-d. Transactionscope) dans ce cas. P> p>