Einzelnen Beitrag anzeigen

Alt 19.10.2006, 06:26   #2
Andreas Kosch
Forenheld
 
Andreas Kosch ist offline
Registriert seit: 26.02.2003
Beiträge: 12.127
Andreas Kosch befindet sich auf einem aufstrebenden Ast
Standard

Hallo,

>...muss ich mich von den DataSet's verabschieden ...

nein.

Dieses Problem und die alternativen Lösungswege habe ich in meiner Tipps&Tricks-Session auf der BASTA!2006 vorgestellt, in der nächsten und übernächsten Ausgabe des dot.net magazin wird der TableAdapter und das Transaktionsproblem vorgestellt .

>Mit jedem neuen TableAdapter wird eine neue SqlConnection geöffnet...

Aber nur dann, wenn vorher die SqlConnection nicht bereits geöffnet war. Bei dem folgenden Beispiel tritt das Problem nicht auf:

            testTblTableAdapter.Connection.ConnectionString = " < aktuelle Version >";

            testTblTableAdapter.Connection.Open();

            try

            {

                using (TransactionScope txScope = new TransactionScope())

                {

                    TransactionInformation txInfo = Transaction.Current.TransactionInformation;

                    listBox1.Items.Add(String.Format("{0}: {1}",

                        txInfo.Status, txInfo.DistributedIdentifier));

                    testTblTableAdapter.Fill(tempdbDataSet.TestTbl);

                    tempdbDataSet.TestTbl.Rows[0]["wert"] = "Neu3";

                    testTblTableAdapter.Update(tempdbDataSet);

                    listBox1.Items.Add(String.Format("{0}: {1}",

                        txInfo.Status, txInfo.DistributedIdentifier));

                    txScope.Complete();

                    listBox1.Items.Add(String.Format("{0}: {1}",

                        txInfo.Status, txInfo.DistributedIdentifier));

                }

            }

            finally

            {

                testTblTableAdapter.Connection.Close();

            }



Zur Kontrolle kann man dies auch im SQL Server prüfen:

SELECT spid, status, program_name, cmd

FROM master.dbo.sysprocesses WITH (NOLOCK)

WHERE dbid = DB_ID('tempdb');



Über die partiellen Klassen kann man den TableAdapter jedoch auch um eigene bzw. überladene Methoden erweitern. Über diesen Weg kann mit einer Handvoll von Programmzeilen der "alte Weg" über SqlTransaction nachgerüstet werden:

            testTblTableAdapter.Connection.Open();

            try

            {

                SqlTransaction aTran;

                aTran = testTblTableAdapter.BeginTransaction(testTblTableA dapter.Connection);

                try

                {

                    testTblTableAdapter.Fill(tempdbDataSet.TestTbl);

                    tempdbDataSet.TestTbl.Rows[0]["wert"] = "Neu4";

                    testTblTableAdapter.Update(tempdbDataSet);

                    aTran.Commit();

                }

                catch

                {

                    aTran.Rollback();

                }

            }

            finally

            {

                testTblTableAdapter.Connection.Close();

            }



Die Erweiterung des Beispiel sieht wie folgt aus:

using System;

using System.Data;

using System.Data.SqlClient;

 

namespace ClientCS

{

    partial class tempdbDataSet

    {

        // eigene DataSet-Erweiterungen

    }

}

 

namespace ClientCS.tempdbDataSetTableAdapters

{

    partial class TestTblTableAdapter

    {

        public SqlTransaction BeginTransaction(SqlConnection aCon)

        {

            if (aCon.State != ConnectionState.Open)

            {

                throw new ArgumentException("Die Datenbankverbindung ist noch geschlossen!");

            }

            Connection = aCon;

            SqlTransaction aTran = Connection.BeginTransaction();

            foreach (SqlCommand cmd in this.CommandCollection)

            {

                if (cmd != null)

                    cmd.Transaction = aTran;

            }

            if ((Adapter.InsertCommand != null))

            {

                Adapter.InsertCommand.Transaction = aTran;

            }

            if ((Adapter.DeleteCommand != null))

            {

                Adapter.DeleteCommand.Transaction = aTran;

            }

            if ((Adapter.UpdateCommand != null))

            {

                Adapter.UpdateCommand.Transaction = aTran;

            }

            if ((Adapter.SelectCommand != null))

            {

                Adapter.SelectCommand.Transaction = aTran;

            }

            return aTran;

        }

    }

}



Da die voreingestellte Basisklasse System.ComponentModel.Component des TableAdapters im Eigenschaftsdialog über die Eigenschaft BaseClass ausgetauscht werden kann, kann allen im Projekt vorhandenen TableAdaptern eine eigene Erweiterung "untergeschoben" werden (auch wenn dies dann nur greift, wenn dort über Reflection die "nachfolgenden" TableAdapter-Teile geändert werden).

>Der ConnectionString wird für jedes einzelne Business Logic Projekt in der app.config gespeichert...

Diese Vorbelegung ist für den TableAdapter nicht zwingend notwendig. Auf Wunsch darf die app.config aus dem Projekt (Bsp: Class Library kapselt den TableAdapter ein) auch entfernt werden - dann allerdings muss vor dem Öffnen der Datenbankverbindung die Verbindungszeichenfolge in eigener Regie initialisiert werden.
&#10
  Mit Zitat antworten

Anzeige