Announcement

Collapse
No announcement yet.

Werte in zwei Tabellen eintagen / Rollback

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Werte in zwei Tabellen eintagen / Rollback

    Hallo zusammen,
    ich habe zwei Tabellen, Autoren und Bücher.
    Wie stelle ich es an, dass wenn ich einen „neuen Autor“ in die Tabelle Autoren eingebe und gleichzeitig dessen Bücher in die Tabelle Bücher.
    Sollte die Eingabe der Bücher nicht klappen, soll auch gleichzeitig ein Rollback des neuen Autors ablaufen.

    Hier der Skript für die Tabellen:

    CREATE TABLE [dbo].[Buecher] (
    [IDB] [int] IDENTITY (1, 1) NOT FOR REPLICATION NOT NULL ,
    [IDA] [int] NOT NULL ,
    [Buchtitel] [nvarchar] (200) COLLATE Latin1_General_CI_AS NOT NULL
    ) ON [PRIMARY]
    GO

    ALTER TABLE [dbo].[Autoren] ADD
    CONSTRAINT [PK_Autoren] PRIMARY KEY CLUSTERED
    (
    [IDA]
    ) ON [PRIMARY]
    GO

    ALTER TABLE [dbo].[Buecher] ADD
    CONSTRAINT [FK_Buecher_Autoren] FOREIGN KEY
    (
    [IDA]
    ) REFERENCES [dbo].[Autoren] (
    [IDA]
    )
    GO

    Ich hoffe mir kann jemand weiterhelfen. Bin für jeden Tipp dankbar....

  • #2
    Hallo,
    um diese Anforderung zu erfüllen, müssen beide INSERT-Aufruf in der gleichen Transaktion ausgeführt werden. Die Vorgehensweise hängt dabei davon ab, wie der Client auf die Datenbank zugreift. Es stehen mehrere Alternativen zur Verfügung:
    1. T-SQL-Anweisungen BEGIN TRANSACTION und COMMIT bzw. ROLLBACK TRANSACTION
    2. Deklarative Transaktionen von COM+ (DTC)
    3. BeginTrans-Methode des Recordset-Objekts von ADO
    4. SqlTransaction-Klasse von ADO.NET 1.0
    5. TransactionScope-Klasse von ADO.NET 2.

    Comment


    • #3
      Ich arbeite mir VB 2005 also ADO.Net 2.0.
      Ist TransactionScope-Klasse neu?

      Wie wende ich diese an

      Comment


      • #4
        Hallo,

        im .NET Framework 2.0 steht der neue Namespace <i>System.Transaction</i> zur Verfügung, dessen Klassen für die Implementierung von verteilten Transaktionen (2-Phase-Commit) zuständig sind. Mit Hilfe dieser Klasse entfällt die Notwendigkeit, dass eigene Geschäftsobjekt von der Klasse <i>ServiceComponent</I> abzuleiten, so dass zusätzliche zu den .NET Enterprise Services diese Funktionalität auch im kompletten .NET Framework verfügbar ist. Die Klassen aus dem Namespace <i>System.Transaction</i> sind zwar universell für alle Datenbanken (bzw. andere Provider wie zum Beispiel MSMQ) geeignet, aber im besonderen Fall des MS SQL Server 2005 stehen zusätzliche Funktionen zur Verfügung, die automatisch den Overhead immer dann vermeiden, wenn er nicht notwendig ist.
        Die Klassen unterstützen sowohl implizite (automatische) als auch explizite (manuelle) Transaktionen. Die Zeitdauer der Gültigkeit eines Transaktions-Kontextes legt auch fest, wann eine Datenbankverbindung wieder für den Datenbankverbindungs-Pool zur Verfügung steht. Solange eine Verbindung noch in einem Transaktions-Kontext steht, legt das Schließen der Verbindung diese nicht sofort in den Pool zurück - dies passiert erst nach dem Freigeben des Transaktions-Kontextes.

        Das folgende Grundgerüst demonstriert das Prinzip:

        <div style="font-family: Courier New; font-size: 10pt; color: black; background: white; border-top: windowtext 1pt solid; padding-top: 0pt; border-left: windowtext 1pt solid; padding-left: 0pt; border-right: windowtext 1pt solid; padding-right: 0pt; border-bottom: windowtext 1pt solid; padding-bottom: 0pt;"><p style="margin: 0px;"><span style="color: green;">' Dem Projekt einen Verweis zu System.Transaction hinzufügen, </span></p><p style="margin: 0px;"><span style="color: green;">' dann über Imports den Namespace einbinden</span></p><p style="margin: 0px;"><span style="color: blue;">Imports</span> System.Transactions</p><p style="margin: 0px;"><span style="color: blue;">Imports</span> System.Data.SqlClient</p><p style="margin: 0px;">&nbsp;</p><p style="margin: 0px;"><span style="color: blue;">Public</span> <span style="color: blue;">Class</span> Form1</p><p style="margin: 0px;">&nbsp;</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">Private</span> <span style="color: blue;">Sub</span> Button1_Click(<span style="color: blue;">ByVal</span> sender <span style="color: blue;">As</span> System.Object, _</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp; <span style="color: blue;">ByVal</span> e <span style="color: blue;">As</span> System.EventArgs) <span style="color: blue;">Handles</span> Button1.Click</p><p style="margin: 0px;">&nbsp;</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; SqlConnection1.Open()</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">Try</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">Using</span> txScope <span style="color: blue;">As</span> TransactionScope = <span style="color: blue;">New</span> TransactionScope()</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: green;">'</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; SqlCommand1.ExecuteNonQuery()</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: green;">'</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; SqlCommand2.ExecuteNonQuery()</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: green;">'</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; txScope.Complete()</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">End</span> <span style="color: blue;">Using</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">Finally</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; SqlConnection1.Close()</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">End</span> <span style="color: blue;">Try</span></p><p style="margin: 0px;">&nbsp;</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">End</span> <span style="color: blue;">Sub</span></p><p style="margin: 0px;"><span style="color: blue;">End</span> <span style="color: blue;">Class</span></p></div&gt

        Comment


        • #5
          Hallo Andreas,
          ich habe festgestellt, dass für TransactionScope der msdtc gestartete sein muss. Dieser Dienst ist aber nicht bei allen PC`s standardmässig gestartet. Gibt es eine Möglichkeit dies per Code abzufragen und im Fall das der Dienst nicht gestartet ist, diesen per Code zu starten bevor die Klasse TransactionScope instanziert wird

          Comment


          • #6
            Hallo,
            beim Zugriff auf den SQL Server 2005 gibt es eine Besonderheit. Solange nur eine einzige Datenbankverbindung besteht, ist nur eine so genannte Lightweight Transaction (alias Smart Transaction) aktiv. Diese Transaktion wird nur innerhalb des .NET Frameworks ohne Beteiligung des Microsoft Distributed Transaction Coordinator (DTC) verwaltet. Sobald im Transaktions-Kontext eine zweite Datenbankverbindung ins Spiel kommt, erweitert sich der Kontext von der Smart Transaktion zu einer verteilten Transaktion, die vom Microsoft Distributed Transaction Coordinater (DTC) kontrolliert wird (also dem Systembestandteil, der diesen Job auch in COM+ beziehungsweise in .NET Enterprise Service erledigt).

            Über <b>Transaction.Current.TransactionInformation</b> kann man überwachen, ob zum DTC gewechselt wird (Eigenschaft <b>DistributedIdentifier</b>).

            Wenn die eigene Anwendung die Verbindung zur Datenbank (SqlConnection-Instanz) in eigener Regie über <b>Open</b> und <b>Close</b> kontrolliert, läuft in der Regel alles über die gleiche Datenbankverbindung ab. In diesem Fall eskaliert die Lightweight Transaction nicht zur DTC-Transaktion.

            Alternativ steht jedoch auch noch der "alte" Weg von .NET 1.x zur Verfügung, indem <b>SqlTransaction</b> verwendet wird:

            <div style="font-family: Courier New; font-size: 10pt; color: black; background: white; border-top: windowtext 1pt solid; padding-top: 0pt; border-left: windowtext 1pt solid; padding-left: 0pt; border-right: windowtext 1pt solid; padding-right: 0pt; border-bottom: windowtext 1pt solid; padding-bottom: 0pt;"><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">Dim</span> aTran <span style="color: blue;">As</span> System.Data.SqlClient.SqlTransaction</p><p style="margin: 0px;">&nbsp; <span style="color: blue;">Me</span>.SqlConnection1.Open()</p><p style="margin: 0px;">&nbsp; aTran = <span style="color: blue;">Me</span>.SqlConnection1.BeginTransaction()</p><p style="margin: 0px;">&nbsp; <span style="color: blue;">With</span> <span style="color: blue;">Me</span>.SqlDataAdapter1</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; .InsertCommand.Transaction = aTran</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; .UpdateCommand.Transaction = aTran</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; .DeleteCommand.Transaction = aTran</p><p style="margin: 0px;">&nbsp; <span style="color: blue;">End</span> <span style="color: blue;">With</span></p><p style="margin: 0px;">&nbsp; <span style="color: blue;">Try</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">Me</span>.SqlDataAdapter1.Update(<span style="color: blue;">Me</span>.DataSet11, sTblName)</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; aTran.Commit()</p><p style="margin: 0px;">&nbsp; <span style="color: blue;">Catch</span> aExc <span style="color: blue;">As</span> Exception</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; aTran.Rollback()</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; aTran = <span style="color: blue;">Nothing</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; MessageBox.Show(aExc.Message)</p><p style="margin: 0px;">&nbsp; <span style="color: blue;">Finally</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">Me</span>.SqlConnection1.Close()</p><p style="margin: 0px;">&nbsp; <span style="color: blue;">End</span> <span style="color: blue;">Try</span></p></div&gt

            Comment


            • #7
              OK.
              Ich habe eine andere Anwendung, wo ich mich durch tricksen beholfen hatte. Für diese Anwendung wäre es sehr interessant "eine" Transaction über mehrere Datenbanken durchzuführen und bei nicht geligen ein Rollback über alle Datenbanken.....

              Aus diesem Grund würde ich gern noch mal die Frage aufrgreifen wollen, ob und wie man den Dienst per Code starten kann...

              Wäre super wenn mir da jemand weiterhelfen könnte...

              Comment


              • #8
                Hallo,
                das ist alles eine Frage der Rechte, die der Benutzer hat. Wenn der Anwender zur Gruppe der Administratoren gehört, kann er über WMI oder <i>net start</i> den Dienst starten. Das geht selbstverständlich nur dann, wenn dieser Teil über die Systemsteuerung | Software | Windows-Komponenten <b>vorher</b> mit installiert wurde (ansonsten fragt das Betriebssystem nach der CDROM von Windows, vor der die Daten nachinstalliert werden sollen..).

                Außerdem muss bei Windows 2003 über <i>Systemsteuerung | Software | Windows-Komponenten hinzufügen</i> | geprüft werden, ob die Option <i>COM+ Netzwerkzugriff aktivieren</i> sowie <i>DTC-Netzwerkzugriff aktivieren</i> ausgewählt sind.

                Lange Rede - kurzer Sinn. Die Konfiguration des DTC hat signifikante Auswirkungen auf die Sicherheit des Rechners, so dass diese Einstellung <b>unabhängig</b> ein einem bestimmten Programm vorgenommen werden muss. Die eigene Anwendung muss im Worst Case den Anwender darüber informieren, dass das Programm erst dann genutzt werden kann, wenn der DTC von einem dazu Berechtigten konfiguriert wurde

                Comment


                • #9
                  Das heißt doch aber das man mit einer Verteilten Application diese neue Klasse, wenn man das über mehrere Datenbanken anwenden will, gar nicht nutzen kann.... oder

                  Comment


                  • #10
                    Hallo,
                    der Zugriff auf verteilte Datenbanken und somit die Notwendigkeit zu verteilten Transaktionen ist eher im Firmenumfeld (aber nicht bei einem privaten Anwender) üblich. Dort werden alle beteiligten PC entsprechend (einheitlich) vorbereitet. Die Anwendung formuliert alle Voraussetzungen, die erfüllt werden müssen. Bevor die Anwendung installiert wird, muss der zuständige Administrator die Voraussetzungen schaffen (d.h. den DTC aktivieren)

                    Comment

                    Working...
                    X