| 

.NET C# Java Javascript Exception

2
Eine Frage, auf die ich trotz einiger Suche im Internet keine Antwort gefunden habe.

Meine Applikation baut während dem Programmstart eine Verbindung zum SQL Server auf. An dieser Stelle würde ich gerne einige Daten bezüglich der aktuellen Session im SQL Server speichern (etwa den Username innerhalb meines Programms, den Namen des Rechners, eine eindeutige ID die die Programmsitzung identifiziert, etc.), so dass ich an späteren Stellen im Programm (insbesondere innerhalb von SQL Stored Procedures) jederzeit darauf zugreifen kann, ohne diese jedesmal mit übergeben zu müssen.

Dabei würde ich diese Variablen gerne innerhalb von Triggern nutzen, um eine automatische Historie mitschreiben zu können (wer hat wann von welchem PC mit welchem Username unter welcher Windows-Anmeldung einen Datensatz geändert). Hätte halt den Vorteil, dass ich mich um eine Änderungshistorie der Datensätze nirgends kümmern müsste, weil ja der SQL Server alles schön brav selbst mitschreiben könnte.

Ist sowas möglich und machbar?
27.06.2011
commänder 420 1 7
3 Antworten
1
Den Application-Namen kannst du im Connection-String mitgeben:

Provider=SQLOLEDB;...;Application Name=MeineAnwendung;

Select APP_NAME() as currentApplication


Die Sache mit dem Usernamen würde ich durch Windows-Authentication lösen.

Provider=SQLOLEDB;...;Integrated Security=SSPI;

SELECT SYSTEM_USER as CurrentUser


Weitere Informationen kannst du Sitzungsbezogen (dh. pro Connection) in Temptabellen speichern und wie normale Tabellen benutzen. Sobald die Connection geschlossen wird, werden auch die Temp-Tabellen gelöscht.

CREATE TABLE [dbo].[#sessiondata] (
[key] varchar(100),
[value] varchar(100)
)
27.06.2011
Floyd 14,6k 3 9
SYSTEM_USER klappt leider in meinem Fall nicht, da bei den Kunden nicht immer eine Domäne vorhanden ist, Windows Authentication ist also keine Option...

Mit temporären Tabellen habe ich schon rumprobiert, ist auf jeden Fall eine Option.

Aber als kleine Erweiterung: Ums mir einfach zu machen, wollte ich die Spalten in der Audit-Tabelle einfach per Default-Wert füllen. Eine Stored Function kann aber leider nicht auf temporäre Tabellen zugreifen. Der Trigger hingegen kann es schon. Muss ich mir wohl doch etwas mehr Arbeit machen...
commänder 28.06.2011
Natürlich können functions nicht auf TempTabellen zugreifen da diese nicht deterministisch sind. Hier muss man sich was anderes einfallen lassen.
Floyd 28.06.2011
Ich würde keine Windows-Authentication empfehlen.
Das widerspricht imho dem Konzept des Connection-Poolings, was gerade bei einer größeren Anwendung die Performance negativ beinflussen dürfte.

Die Idee mit der autom. Historie ist zwar nett, aber Trigger sind für mich immer die letzte Wahl.

Wir verwenden für unsere Historien Stored-Procedures, eine ganz normale Logging-Tabelle und die Anwendung verwaltet die benutzerbezogenen Daten.

Btw, denk auch den Datenschutz - in einigen Unternehmen, ist so ein Logging nicht erlaubt.
mblaess 29.06.2011
Windows-Authentication ist trotzdem empfehlenswert wenn man einzelnen Benutzern oder Benutzergruppen spezielle Zugriffsrechte zuweisen will. Als Beispiel: Ein normaler Sachbearbeiter im Innendienst sollte nicht Zugriff auf die Buchhaltungsdatenbanken bekommen und umgekehrt. Das Problem mit den Connection-Pools ist nur in sofern ein Problem das ich einen entsprechend potenten SQL-Server brauche.
Für Webseiten wie Facebook oder CK wäre Windows-Authentication eh nicht praktikabel und somit hat man hier kein Problem mit den Connection-Pools.
Floyd 29.06.2011
Und ich bevorzuge ehrlich gesagt Tricker als History-Schreiber weil man Sie nichtt vergessen kann. Wenn man alleine arbeitet ist es sicherlich Problemlos möglich sicherzustellen das man immer Proceduren verwenden. In Teams kann ich aber meine Hand nicht für alle Mit-Programmierer ins Feuer legen und verwenden lieber Tricker.
Floyd 29.06.2011
1
@mblaess: Was spricht gegen den Einsatz von Triggern, warum siehst du diese als "letzte Wahl"? Gibts dafür handfeste Gründe, oder eher eine persönliche Abneigung?
commänder 30.06.2011
Ich Trigger sind etwas komplizierter, insbesondere wenn man Multi-Row Unterstützung einbauen muss.
Abgesehen davon können unerwartet Side Effects und Recusion auftreten.
Floyd 30.06.2011
1
@commänder:
Floyd hat schon einige Gründe genannt, die mich oftmals davon abhalten Trigger zu verwenden.
Gerade bei großen Datenbanken mit vielen Tabellen, wird das schnell unübersichtlich.
Ich habe schon einige Programmierer in die Tastatur beißen sehen, weil sie stundenlang einen Fehler gesucht haben, der durch einen Trigger "ausgelöst" wurde :-(
Btw, hier ist eine sehr schöne Diskussion bei der die Vor- und Nachteile von Triggern bei Historientabellen behandelt wird:

http://stackoverflow.com/questions/1250507/history-tables-pros-cons-and-gotchas-using-triggers-sproc-or-at-application-l
mblaess 01.07.2011
1
Wenn der Trigger immer für alle Tabellen gleich ist, also in dem Trigger selber keine Logik steckt, sind Trigger die beste Wahl. Alleine aus dem Grund den Floyd schon genannt hat. Man kann es nicht vergessen. Nimmt man einen "manuellen" Ansatz, wird es zu 100% irgendwann mal vergessen.
Khalid 01.07.2011
1
Hallo,

du kannst alternativ auch SET CONTEXT_INFO nutzen. Nach dem Herstellen der Verbindung zum SQL Server ruft du sofort SET CONTEXT_INFO auf und kannst dann in allen Triggern und SPs auf diese Daten mittels CONTEXT_INFO() zugreifen.

In den Kontextinformationen kannst du 128 Byte Daten speichern, die während der gesamten Session dir dann zur Verfügung stehen (VARBINARY(128)). Ich benutze dies ebenfalls für Auditing Zwecke (da ebenfalls möglicherweise keine Windows Domaine zur Verfügung steht) und funktioniert bis jetzt ganz gut.
28.06.2011
Khalid 490 2
1
Ich habe das mit 2 Tabellen gelöst: Session und SessionSPID.

Session enthält die Sitzungsdaten des Benutzers, der gerade in der Anwendung angemeldet ist.

SessionSPID ist die Zuordnung einer Session zu einer oder mehreren @@SPID's.

Bei jedem SqlConnection.Open() wird eine SP aufgerufen, die diese Zuordnung für die aktuelle Connection herstellt:

CREATE PROCEDURE [dbo].[Set_SessionSPID](
@SessionID INT
) AS

DELETE FROM SessionSPID
WHERE SPID = @@SPID

INSERT INTO SessionSPID (SessionID, SPID)
SELECT @SessionID, @@SPID
FROM Session
INNER JOIN AppUser ON Session.UserID = AppUser.ID
WHERE Session.OID = @SessionID


Da die @@SPID während einer geöffneten SqlConnection konstant ist, kann in TSQL jederzeit über die Abfrage

SELECT SessionID FROM Session WHERE SPID = @@SPID


der Benutzer bzw. dessen Session abgefragt werden.
29.06.2011
devio 302 3

Stelle deine Sql-Frage jetzt!