In diesem Code gibt es mehrere Probleme, die behoben werden müssen:
-
In Bezug auf die angegebene Frage, wenn Sie eine System.Security.SecurityException erhalten Fehler, der sich auf den Code bezieht, der versucht, außerhalb der Datenbank zu gelangen, etwas, das in einem
SAFE
nicht erlaubt ist Montage. Wie Sie dies beheben, hängt davon ab, was Sie erreichen möchten.- Wenn Sie versuchen, auf das Dateisystem zuzugreifen, aus der Registrierung zu lesen, eine Umgebungsvariable abzurufen, auf das Netzwerk für eine Nicht-SQL-Server-Verbindung (z. B. http, ftp) zuzugreifen usw., dann benötigt die Assembly einen
PERMISSION_SET
vonEXTERNAL_ACCESS
. Um Ihre Assembly auf etwas anderes alsSAFE
einzustellen , müssen Sie entweder:- Erstellen Sie ein Zertifikat oder einen asymmetrischen Schlüssel basierend auf demselben Schlüssel, den Sie zum Signieren Ihrer Assembly verwendet haben (d. h. geben Sie ihr einen starken Namen), erstellen Sie eine Anmeldung basierend auf diesem Zertifikat oder asymmetrischen Schlüssel und gewähren Sie dann den
EXTERNAL ACCESS ASSEMBLY
Berechtigung zu diesem Login. Diese Methode ist großartig gegenüber der anderen Methode bevorzugt, nämlich: - Setzen Sie die Datenbank, die die Assembly enthält, auf
TRUSTWORTHY ON
. Diese Methode sollte immer nur als letztes Mittel verwendet werden, wenn es nicht möglich ist, die Versammlung zu signieren. Oder für schnelle Testzwecke. Setzen einer Datenbank aufTRUSTWORTHY ON
öffnet Ihre Instanz potenziellen Sicherheitsbedrohungen und sollte vermieden werden, auch wenn es schneller/einfacher ist als die andere Methode.
- Erstellen Sie ein Zertifikat oder einen asymmetrischen Schlüssel basierend auf demselben Schlüssel, den Sie zum Signieren Ihrer Assembly verwendet haben (d. h. geben Sie ihr einen starken Namen), erstellen Sie eine Anmeldung basierend auf diesem Zertifikat oder asymmetrischen Schlüssel und gewähren Sie dann den
-
Wenn Sie versuchen, auf die SQL Server-Instanz zuzugreifen, bei der Sie bereits angemeldet sind, haben Sie die Möglichkeit, die In-Process-Verbindung von
Context Connection = true;
zu verwenden was in einemSAFE
erfolgen kann Montage. Dies hat @Marc in seiner Antwort vorgeschlagen. Obwohl die Verwendung dieser Art von Verbindung definitiv Vorteile hat und die Kontextverbindung in diesem speziellen Szenario die richtige Wahl war, ist es zu einfach und falsch zu sagen, dass Sie immer sollten Verwenden Sie diese Art der Verbindung. Sehen wir uns die positiven und negativen Aspekte der Kontextverbindung an :- Positive:
- Kann in einem
SAFE
durchgeführt werden Montage. - Sehr geringer Verbindungsaufwand, wenn überhaupt, da es sich nicht um eine zusätzliche Verbindung handelt.
- Ist Teil der aktuellen Sitzung, sodass jedes von Ihnen ausgeführte SQL Zugriff auf sitzungsbasierte Elemente wie lokale temporäre Tabellen und
CONTEXT_INFO
hat .
- Kann in einem
-
Negative:
- Kann nicht verwendet werden, wenn Identitätswechsel aktiviert wurde.
- Kann nur eine Verbindung zur aktuellen SQL Server-Instanz herstellen.
- Wenn es in Funktionen (Skalar und Tabellenwert) verwendet wird, hat es dieselben Einschränkungen wie T-SQL-Funktionen (z. B. sind keine Operationen mit Nebeneffekten zulässig), außer dass Sie schreibgeschützte gespeicherte Prozeduren ausführen können.
- Tabellenwertfunktionen dürfen ihre Ergebnisse nicht zurückstreamen, wenn sie eine Ergebnismenge lesen.
Alle diese "Negativen" sind erlaubt, wenn eine normale/externe Verbindung verwendet wird, selbst wenn es sich um dieselbe Instanz handelt, von der aus Sie diesen Code ausführen.
- Positive:
- Wenn Sie versuchen, auf das Dateisystem zuzugreifen, aus der Registrierung zu lesen, eine Umgebungsvariable abzurufen, auf das Netzwerk für eine Nicht-SQL-Server-Verbindung (z. B. http, ftp) zuzugreifen usw., dann benötigt die Assembly einen
-
Wenn Sie eine Verbindung zu der Instanz herstellen, von der aus Sie diesen Code ausführen, und eine externe/normale Verbindung verwenden, müssen Sie den Servernamen nicht angeben oder sogar
localhost
verwenden . Die bevorzugte Syntax istServer = (local)
das Shared Memory verwendet, während die anderen manchmal TCP/IP verwenden, was nicht so effizient ist. -
Verwenden Sie
Persist Security Info=True;
nicht, es sei denn, Sie haben einen ganz bestimmten Grund dafür -
Es hat sich bewährt,
Dispose()
zu verwenden IhresSqlCommand
-
Es ist effizienter,
insertcommand.Parameters.Add()
aufzurufen direkt vor demfor
Schleife und setzen Sie dann innerhalb der Schleife einfach den Wert überfirstname.Value =
, was Sie bereits tun, also verschieben Sie einfachinsertcommand.Parameters.Add()
Zeilen bis kurz vorfor
Linie. -
tel
/@tel
/listtelnumber
sindINT
stattVARCHAR
/string
. Telefonnummern, genau wie Postleitzahlen und Sozialversicherungsnummern (SSNs), sind nicht Nummern, auch wenn sie so aussehen.INT
führendes0
kann nicht gespeichert werden s oder so etwas wieex.
um eine "Erweiterung" anzuzeigen. -
All dies gesagt, selbst wenn alle oben genannten Punkte korrigiert werden, gibt es immer noch ein riesiges Problem mit diesem Code, das angegangen werden sollte :Dies ist eine ziemlich einfache Operation, die in direktem T-SQL ausgeführt werden kann, und dies in SQLCLR zu tun, ist zu kompliziert, schwieriger und kostspieliger zu warten und viel langsamer. Dieser Code führt 10.000 separate Transaktionen durch, während er so einfach als eine einzige satzbasierte Abfrage (d. h. eine Transaktion) durchgeführt werden könnte. Sie könnten Ihren
for
umschließen Schleife in einer Transaktion, was sie beschleunigen würde, aber sie ist immer noch langsamer als der satzbasierte T-SQL-Ansatz, da sie immer noch 10.000 separateINSERT
ausgeben muss Aussagen. Sie können in T-SQL einfach randomisieren, indem Sie entwederNEWID()
verwenden oder CRYPT_GEN_RANDOM die in SQL Server 2008 eingeführt wurde. (siehe UPDATE Abschnitt unten)
Wenn Sie mehr über SQLCLR erfahren möchten, sehen Sie sich bitte die Serie an, die ich für SQL Server Central schreibe: Treppe zu SQLCLR (kostenlose Registrierung erforderlich).
AKTUALISIEREN
Hier ist eine reine T-SQL-Methode zum Generieren dieser Zufallsdaten unter Verwendung der Werte aus der Frage. Es ist einfach, neue Werte zu jeder der 4 Tabellenvariablen hinzuzufügen (um die Anzahl möglicher Kombinationen zu erhöhen), da die Abfrage den Randomisierungsbereich dynamisch anpasst, damit er zu den Daten passt, die in jeder Tabellenvariablen enthalten sind (d. h. Zeilen 1 - n).
DECLARE @TelNumber TABLE (TelNumberID INT NOT NULL IDENTITY(1, 1),
Num VARCHAR(30) NOT NULL);
INSERT INTO @TelNumber (Num) VALUES ('1525407'), ('5423986'), ('1245398'), ('32657891'),
('123658974'), ('7896534'), ('12354698');
DECLARE @FirstName TABLE (FirstNameID INT NOT NULL IDENTITY(1, 1),
Name NVARCHAR(30) NOT NULL);
INSERT INTO @FirstName (Name) VALUES ('Babak'), ('Carolin'), ('Martin'), ('Marie'),
('Susane'), ('Michail'), ('Ramona'), ('Ulf'), ('Dirk'), ('Sebastian');
DECLARE @LastName TABLE (LastNameID INT NOT NULL IDENTITY(1, 1),
Name NVARCHAR(30) NOT NULL);
INSERT INTO @LastName (Name) VALUES ('Bastan'), ('Krause'), ('Rosner'),
('Gartenmeister'), ('Rentsch'), ('Benn'), ('Kycik'), ('Leuoth'),
('Kamkar'), ('Kolaee');
DECLARE @Address TABLE (AddressID INT NOT NULL IDENTITY(1, 1),
Addr NVARCHAR(100) NOT NULL);
INSERT INTO @Address (Addr) VALUES ('Deutschlan Chemnitz Sonnenstraße 59'), (''),
('Deutschland Chemnitz Arthur-Strobel straße 124'),
('Deutschland Chemnitz Brückenstraße 3'),
('Iran Shiraz Chamran Blvd, Niayesh straße Nr.155'), (''),
('Deutschland Berlin Charlotenburg Pudbulesky Alleee 52'),
('United State of America Washington DC. Farbod Alle'), ('');
DECLARE @RowsToInsert INT = 10000;
;WITH rowcounts AS
(
SELECT (SELECT COUNT(*) FROM @TelNumber) AS [TelNumberRows],
(SELECT COUNT(*) FROM @FirstName) AS [FirstNameRows],
(SELECT COUNT(*) FROM @LastName) AS [LastNameRows],
(SELECT COUNT(*) FROM @Address) AS [AddressRows]
), nums AS
(
SELECT TOP (@RowsToInsert)
(CRYPT_GEN_RANDOM(1) % rc.TelNumberRows) + 1 AS [RandomTelNumberID],
(CRYPT_GEN_RANDOM(1) % rc.FirstNameRows) + 1 AS [RandomFirstNameID],
(CRYPT_GEN_RANDOM(1) % rc.LastNameRows) + 1 AS [RandomLastNameID],
(CRYPT_GEN_RANDOM(1) % rc.AddressRows) + 1 AS [RandomAddressID]
FROM rowcounts rc
CROSS JOIN msdb.sys.all_columns sac1
CROSS JOIN msdb.sys.all_columns sac2
)
-- INSERT dbo.Unsprstb(Firstname, Lastname, Tel, Address)
SELECT fn.Name, ln.Name, tn.Num, ad.Addr
FROM @FirstName fn
FULL JOIN nums
ON nums.RandomFirstNameID = fn.FirstNameID
FULL JOIN @LastName ln
ON ln.LastNameID = nums.RandomLastNameID
FULL JOIN @TelNumber tn
ON tn.TelNumberID = nums.RandomTelNumberID
FULL JOIN @Address ad
ON ad.AddressID = nums.RandomAddressID;
Hinweise:
- Der
FULL JOIN
s werden anstelle vonINNER JOIN
benötigt s, um den gesamten@RowsToInsert
zu erhalten Anzahl der Zeilen. - Doppelte Zeilen sind aufgrund der Art dieser Randomisierung möglich UND werden nicht mit
DISTINCT
herausgefiltert . AllerdingsDISTINCT
kann nicht mit den angegebenen Beispieldaten in der Frage verwendet werden, da die Anzahl der Elemente in jeder Array- / Tabellenvariablen nur 6300 eindeutige Kombinationen vorsieht und die angeforderte Anzahl der zu generierenden Zeilen 10.000 beträgt. Wenn den Tabellenvariablen weitere Werte hinzugefügt werden, sodass die insgesamt möglichen eindeutigen Kombinationen über die angeforderte Anzahl von Zeilen hinausgehen, dann wird entwederDISTINCT
Schlüsselwort kann zu dennums
hinzugefügt werden CTE, oder die Abfrage kann einfach zuCROSS JOIN
umstrukturiert werden alle Tabellenvariablen enthalten einROW_COUNT()
Feld und schnappen Sie sichTOP(n)
mitORDER BY NEWID()
. - Das
INSERT
ist auskommentiert, damit Sie leichter erkennen können, dass die obige Abfrage das gewünschte Ergebnis liefert. Kommentieren Sie einfachINSERT
aus damit die Abfrage die eigentliche DML-Operation durchführt.