Frage

Ich bin derzeit ein Legacy-System zu aktualisieren, die Benutzer Teil des Schemas eines seiner Tabellen diktieren kann. Benutzer können Spalten aus der Tabelle über diese Schnittstelle erstellen und entfernen. Das Legacy-System wird mit ADO 2.8 und wird mit Hilfe von SQL Server 2005 als Datenbank (Sie wollen nicht einmal wissen, welche Datenbank es wurde mit bevor der Versuch, dieses Tier zu modernisieren begann ... aber ich schweife ab. =))

In diesem gleichen Bearbeitungsprozess können Benutzer definieren (und aus) einer Liste der gültigen Werte, die in diesem Benutzer erstellt Feldern gespeichert werden können (wenn der Benutzer beschränken will, was im Bereich sein kann).

Wenn der Benutzer die Liste der gültigen Einträge für ein Feld ändert, wenn sie eine der gültigen Werte entfernen, dürfen sie einen neuen „gültigen Wert“ wählen, alle Zeilen kartieren, die diese (jetzt ungültig) Wert darin haben , so dass sie jetzt wieder einen gültigen Wert haben.

durch den alten Code in suchen, bemerkte ich, dass es extrem anfällig ist, das System in einen ungültigen Zustand zu bringen, da die oben genannten Änderungen nicht innerhalb einer Transaktion durchgeführt werden (so, wenn jemand andere auf halbem Weg durch den Prozess kommt oben erwähnt und machte ihre eigenen Änderungen ... na ja, können Sie die Probleme vorstellen, dass verursachen könnte).

Das Problem ist, ich habe versucht, sie unter einer einzigen Transaktion zu aktualisieren zu bekommen, aber wenn der Code zum Teil bekommt, wo es das Schema der Tabelle ändert, alle anderen Änderungen (Aktualisieren von Werten in den Zeilen sei es in der Tabelle, wo das Schema geändert oder nicht ... können sie völlig unabhängig Tabellen selbst sein), die in der Transaktion bis zu diesem Zeitpunkt erscheinen sofort gelöscht werden. Ich erhalte keine Fehlermeldung anzeigt, dass sie fallen gelassen wurden, und als ich die Transaktion am Ende begehen wird kein Fehler ausgelöst ... aber wenn ich gehe in den Tabellen zu suchen, die in der Transaktion aktualisiert werden sollen, nur die neuen Spalten gibt es. Keiner der nicht-Schemaänderungen werden gespeichert.

nach Antworten auf dem Netz suchen hat, so weit, erwies sich als eine Verschwendung von ein paar Stunden sein ... so wende ich mich hier um Hilfe. Hat jemand schon einmal versucht, eine Transaktion über ADO auszuführen, dass sowohl das Schema einer Tabelle und Updates Zeilen in Tabellen aktualisiert (sei es am selben Tisch, oder andere)? Ist es nicht erlaubt? Gibt es eine Dokumentation gibt, die in dieser Situation hilfreich sein könnte?

EDIT:

Okay, ich eine Spur haben, und diese Befehle wurden in die Datenbank (Erläuterungen in Klammern)

gesendet

(ich weiß nicht, was hier geschieht, sieht aus wie es eine temporäre gespeicherte Prozedur zu schaffen ...?)


declare @p1
int set @p1=180150003 declare @p3 int
set @p3=2 declare @p4 int set @p4=4
declare @p5 int set @p5=-1

(retreiving die Tabelle, die Definitionsinformationen für die Benutzer-generierte Felder hält)


exec sp_cursoropen @p1 output,N'SELECT * FROM CustomFieldDefs ORDER BY Sequence',@p3 output,@p4 output,@p5 output select @p1, @p3, @p4, @p5
go

(Ich glaube, mein Code durch die Liste von ihnen hier wurde iteriert, die aktuellen Informationen Rupfen)


exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,1025,1,1
go
exec sp_cursorfetch 180150003,1028,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go

(Dies scheint zu sein, wo ich die geänderten Daten für die Definitionen bin Eingabe, gehe ich durch jeden und alle Änderungen aktualisieren, die in den Definitionen aufgetreten für die benutzerdefinierte selbst Felder)


exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=1,@Description='asdf',@Format='U|',@IsLookUp=1,@Length=50,@Properties='U|',@Required=1,@Title='__asdf',@Type='',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=2,@Description='give',@Format='Y',@IsLookUp=0,@Length=0,@Properties='',@Required=0,@Title='_give',@Type='B',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=3,@Description='up',@Format='###-##-####',@IsLookUp=0,@Length=0,@Properties='',@Required=0,@Title='_up',@Type='N',@_Version=1
go 
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=4,@Description='Testy',@Format='',@IsLookUp=0,@Length=50,@Properties='',@Required=0,@Title='_Testy',@Type='',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=5,@Description='you',@Format='U|',@IsLookUp=0,@Length=250,@Properties='U|',@Required=0,@Title='_you',@Type='',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=6,@Description='never',@Format='mm/dd/yyyy',@IsLookUp=0,@Length=0,@Properties='',@Required=0,@Title='_never',@Type='D',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=7,@Description='gonna',@Format='###-###-####',@IsLookUp=0,@Length=0,@Properties='',@Required=0,@Title='_gonna',@Type='C',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go

(Dies ist, wo mein Code die über die Schnittstelle gelöscht entfernt, bevor diese Einsparung] begann ... es ist auch das einzige, was, soweit ich das sagen kann, passiert eigentlich während dieser Transaktion)


ALTER TABLE CustomizableTable DROP COLUMN _weveknown;

(Nun, wenn eine der Definitionen so verändert wurden, dass die vom Benutzer erstellte Spalte Eigenschaften geändert werden müssen oder Indizes für die Spalten müssen / entfernt hinzugefügt werden, wird es hier getan, zusammen mit geben ein Standardwert auf alle Zeilen, die keinen Wert noch für die gegebene Spalte ... beachten Sie, dass, soweit ich hatte dies sagen kann, NONE passiert eigentlich, wenn die gespeicherte Prozedur beendet ist.)

go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '__asdf'
go
ALTER TABLE CustomizableTable ALTER COLUMN __asdf VarChar(50) NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx___asdf') CREATE NONCLUSTERED INDEX idx___asdf ON CustomizableTable ( 
__asdf ASC) WITH (PAD_INDEX  = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF);
go
select * from IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx___asdf') CREATE NONCLUSTERED INDEX idx___asdf ON 
CustomizableTable ( __asdf ASC) WITH (PAD_INDEX  = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF);
go
UPDATE CustomizableTable SET [__asdf] = '' WHERE [__asdf] IS NULL
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '_give'
go
ALTER TABLE CustomizableTable ALTER COLUMN _give Bit NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx__give') DROP INDEX idx__give ON CustomizableTable WITH ( ONLINE = OFF );
go
UPDATE CustomizableTable SET [_give] = 0 WHERE [_give] IS NULL
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '_up'
go
ALTER TABLE CustomizableTable ALTER COLUMN _up Int NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx__up') DROP INDEX idx__up ON CustomizableTable WITH ( ONLINE = OFF );
go
UPDATE CustomizableTable SET [_up] = 0 WHERE [_up] IS NULL
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '_Testy'
go
ALTER TABLE CustomizableTable ADD _Testy VarChar(50) NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx__Testy') DROP INDEX idx__Testy ON CustomizableTable WITH ( ONLINE = OFF );
go
UPDATE CustomizableTable SET [_Testy] = '' WHERE [_Testy] IS NULL
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '_you'
go
ALTER TABLE CustomizableTable ALTER COLUMN _you VarChar(250) NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx__you') DROP INDEX idx__you ON CustomizableTable WITH ( ONLINE = OFF );
go
UPDATE CustomizableTable SET [_you] = '' WHERE [_you] IS NULL
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '_never'
go
ALTER TABLE CustomizableTable ALTER COLUMN _never DateTime NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx__never') DROP INDEX idx__never ON CustomizableTable WITH ( ONLINE = OFF );
go
UPDATE CustomizableTable SET [_never] = '1/1/1900' WHERE [_never] IS NULL
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '_gonna'
go
ALTER TABLE CustomizableTable ALTER COLUMN _gonna Money NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx__gonna') DROP INDEX idx__gonna ON CustomizableTable WITH ( ONLINE = OFF );
go
UPDATE CustomizableTable SET [_gonna] = 0 WHERE [_gonna] IS NULL
go

(Abschluss der Transaktion ...?)

exec sp_cursorclose 180150003
go

Nach allem, was über ado, nur the Löschen der Spalte auftritt. Alles vor und nach der Transaktion erscheint ignoriert zu werden, und es gab keine Meldungen in dem SQL-Trace, um anzuzeigen, dass etwas schief gelaufen ist während der Transaktion.

War es hilfreich?

Lösung

Der Code wird mit einem serverseitigen Cursor, das ist, was diese Anrufe sind. Die erste Gruppe von Anrufen bereitet / den Cursor zu öffnen. Dann holen Zeilen aus dem Cursor. Schließlich Schließen Sie den Cursor. Diese sprocs sind analog zu den OPEN CURSOR, FETCH NEXT CLOSE CURSOR T-SQL-Anweisungen.

würde ich einen genaueren Blick nehmen (was ich will), aber meine Vermutung ist es etwas los mit dem serverseitigen Cursor ist, die Kapselung Transaktion und die DDL.

Einige weitere Fragen:

  1. das heißt, Sie serverseitige Cursors in diesem Fall zu benutzen?
  2. Sind die ADO-Befehle alle die gleiche aktive Verbindung mit?

Update:

Ich bin mir nicht ganz sicher, was los ist.

Es sieht aus wie Sie serverseitige Cursors verwenden, so dass Sie Recordset.Update () drücken Änderungen zurück an den Server, zusätzlich zu der Ausführung generierten SQL-Anweisungen zu ändern Schema und Aktualisieren von Daten in der dynamischen Tabelle verwenden können (s ). Unter Verwendung der gleichen Verbindung, innerhalb einer expliziten Transaktion.

Ich bin nicht sicher, welche Auswirkungen der Cursor-Operationen auf dem Rest der Transaktion haben werden, oder umgekehrt, und um ehrlich zu sein ich bin überrascht dies nicht funktioniert.

Ich weiß nicht, wie groß eine Änderung wäre es, aber ich würde empfehlen, von dem serverseitige Cursors und dem Aufbau der Update-Anweisungen für Ihre Tabelle Updates weg.

Leider habe ich nicht mehr helfen konnte.

BTW ich folgende Informationen zu den sp_cursor Anrufe gefunden:

http://jtds.sourceforge.net/apiCursors.html

Andere Tipps

Das Verhalten, das Sie beschreiben, ist erlaubt. Wie macht der Code die Schemaänderungen? Der Aufbau SQL on the fly und Ausführung durch einen ADO-Befehl? Oder mit ADOX?

Wenn Sie den Zugriff auf den Datenbankserver haben, versuchen Sie eine SQL Profiler-Ablaufverfolgung ausgeführt wird, während das Szenario testen Sie skizziert. Prüfen Sie, ob der Trace protokolliert alle Fehler / Rollbacks.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top