2016-04-01 11 views
1

Ich muss etwas Code aus dem alten Projekt in das neue verschieben. Altes Projekt verwendet DLL mit gespeicherten Prozeduren (32-Bit-Version), aber ich brauche diese DLL bei 64-Bit SQL Server, also muss ich diese Prozeduren neu schreiben."MS DTC hat die verteilte Transaktion abgebrochen" Fehler in SQLCLR gespeicherte Prozedur

ich mit Stored Procedures schreibe DLL für SQL Server 2008 Management Studio I Assembly laden, dann Prozedur erstellen, indem Sie:

CREATE PROCEDURE ... 
AS EXTERNAL NAME 

Alte DLL Prozeduren nur neue Verbindung zum Remote-SQL-Server verwendet gespeichert laufen Verfahren darauf und Ergebnisse zurückgeben.

Also in meiner Prozedur ich ein SqlConnection auf den Remote-Server erstellen und gespeicherte Prozedur auf dem Remote-Server ausgeführt werden:

using (SqlConnection connection = new SqlConnection(String.Format("User ID={0};Password={1};Persist Security Info=True;Initial Catalog={2};Data Source={3}", Login, Password, DBName, ServerName))) 
{ 
    connection.Open(); 
    SqlCommand command = new SqlCommand("Exec ProcName", connection); 
    SqlDataReader reader = command.ExecuteReader(); 
    SqlContext.Pipe.Send(reader); 
} 

Wenn ich dieses Verfahren in SSMS ausführen, funktioniert es. Aber im alten Projekt wirft es Fehler:

MSDTC-Dienst läuft, und ich setze alle Sicherheitsparameter. Wie behebt man das? Vielleicht gibt es andere Möglichkeiten, entfernte gespeicherte Prozeduren auszuführen (Verbindungsserver), aber ich muss alte Projektfunktionen speichern.

+1

DTC ist an * Transaktionen beteiligt * Veröffentlichen Sie den Code, der * die Transaktion * startet. Ihre gespeicherte Prozedur tut etwas wirklich Böses - sie öffnet einen * neuen Verbindungsserver *, was bedeutet, dass alle bestehenden Transaktionen, die von Ihrem Code gestartet werden, zu verteilten Transaktionen eskalieren müssen, die DTC verwenden. Warum haben Sie nicht einfach einen Verbindungsserver erstellt und die Remote-Prozedur direkt aufgerufen? Um diesen Code auszuführen, musste man sich auch entspannen SQLCLR Sicherheit –

Antwort

1

Es gibt mehrere Dinge, die nicht ganz richtig los hier:

  1. Warum Sie etwas Umschreiben sind? Wenn Sie den Code haben, wird im schlimmsten Fall nur für die neue Architektur neu kompiliert.

  2. Warum machst du irgendwas an erster Stelle? Der Code sollte gegen "Any CPU" (unter "Platform target" in der "SQLCLR Build" -Registerkarte von "Project Properties") und nicht speziell für 32-Bit oder 64-Bit kompiliert werden. Und wenn es schon unter "Irgendeine CPU" kompiliert wurde, dann gibt es nichts zu tun. Haben Sie das neue System getestet, bevor Sie mit dem Neukompilieren und/oder Neuschreiben begonnen haben?

  3. Verwenden Sie nicht String.Format, um die Verbindungszeichenfolge zu erstellen. Stattdessen SqlConnectionStringBuilder verwenden:

    SqlConnectionStringBuilder _ConnectionStringBuilder = 
               new SqlConnectionStringBuilder(); 
    
    _ConnectionStringBuilder.DataSource = ServerName; 
    _ConnectionStringBuilder.InitialCatalog = DBName; 
    _ConnectionStringBuilder.UserID = Login; 
    _ConnectionStringBuilder.Password = Password; 
    
  4. Es sei denn, Sie absolut keine andere Wahl haben und diese Option verwenden müssen, nicht angeben Persist Security Info=True;

  5. Statt new SqlCommand() zu verwenden, erstellen die SqlCommand mit:

    using(SqlCommand command = connection.CreateCommand()) 
    { 
        command.CommandText = "Exec ProcName"; 
    } 
    
  6. Stellen Sie sicher, dass Sie auch command.CommandType = CommandType.StoredProcedure; angeben, damit anstelle einer Ad-hoc-Abfrage ein tatsächlicher RPC-Aufruf ausgeführt wird. Dies erfordert, dass Sie den Text von "EXEC" aus dem aktuellen CommandText von "EXEC ProcName" entfernen; Sie können nur [[DatabaseName.]SchemaName.]ProcName angeben.

  7. SqlDataReader A ist ein Einweg-Objekt, wie SqlConnection und SqlCommand, so dass die SqlDataReader reader = command.ExecuteReader() sollte in einem using() Konstrukt gewickelt werden.

Sobald die Elemente oben korrigiert wurden zur Kenntnis genommen, sollten Sie in der Lage sein, den Fehler zu beheben, indem Sie einfach die folgende Eigenschaft der SqlConnectionStringBuilder Einstellung: _ConnectionStringBuilder.Enlist = false.

Weitere Informationen und Beispiele zum Arbeiten mit SQLCLR finden Sie in der Serie, die ich in SQL Server Central zu diesem Thema verfasse: Stairway to SQLCLR (zum Lesen von Inhalten auf dieser Site ist eine kostenlose Registrierung erforderlich).

+1

1. Ich habe nur Code der alten DLL, nicht das gesamte Projekt. Und dieser Code ist auf Pascal. Das Kompilieren unter XE6 (bis 64Bit) führte zu Problemen mit den Typen und mein Team entschied sich, eine neue Bibliothek zu schreiben, anstatt alten Code zu refactorieren. 3-7 Ich stimme dir zu, danke! Ich muss nur 'Exec' aus dem Befehlstext entfernen, wenn ich 'StoredProcedure' verwende. – cerberus

+0

@cerberus Ja, tut mir leid, dass ich die 'EXEC' nicht entfernen darf, da sie nur '[[DatabaseName.] SchemaName.] ProcName' sein kann. Ich habe vergessen, dass da drin war, da ich versucht habe, die anderen Details nicht zu vergessen ;-). Ich werde meine Antwort aktualisieren, um diesen Teil zu berücksichtigen. Aber wie kommt es, dass der alte Code in Pascal gemacht wird? Meinst du Delphi XE6? Kompiliert XE6 zu .NET MSIL? Laut https://www.embarcadero.com/products/delphi/faq tut es nicht. Oder fehlt mir etwas? –

+0

alter Code ist Delphi 7 Projekt, es verwendet ODS API. also hat es nichts mit .net. Wir haben versucht, XE6 auf 64-Bit-Plattform zu bauen, aber es gab eine Menge Fehler mit Typen. Also entschieden wir uns, auf C# – cerberus