Ada beberapa masalah yang terjadi dalam kode ini yang perlu ditangani:
-
Mengenai pertanyaan yang disebutkan, ketika Anda mendapatkan System.Security.SecurityException kesalahan, yang mengacu pada kode yang mencoba menjangkau di luar basis data, sesuatu yang tidak diizinkan dalam
SAFE
perakitan. Cara Anda memperbaikinya bergantung pada apa yang ingin Anda capai.- Jika Anda mencoba mengakses sistem file, membaca dari registri, mendapatkan variabel lingkungan, mengakses jaringan untuk koneksi non-SQL Server (misalnya http, ftp), dll, maka perakitan memerlukan
PERMISSION_SET
dariEXTERNAL_ACCESS
. Untuk mengatur Majelis Anda ke apa pun selainSAFE
, Anda harus:- Buat Sertifikat atau Kunci Asimetris berdasarkan kunci yang sama dengan yang Anda gunakan untuk menandatangani Majelis Anda (yaitu beri nama yang kuat), buat Login berdasarkan Sertifikat atau Kunci Asimetris tersebut, lalu berikan
EXTERNAL ACCESS ASSEMBLY
izin untuk Login itu. Metode ini sangat lebih disukai daripada metode lainnya, yaitu: - Setel database yang berisi perakitan ke
TRUSTWORTHY ON
. Metode ini hanya boleh digunakan sebagai upaya terakhir jika tidak mungkin untuk menandatangani majelis. Atau untuk tujuan pengujian cepat. Menyetel database keTRUSTWORTHY ON
membuka instans Anda terhadap potensi ancaman keamanan dan harus dihindari, meskipun lebih cepat/mudah daripada metode lainnya.
- Buat Sertifikat atau Kunci Asimetris berdasarkan kunci yang sama dengan yang Anda gunakan untuk menandatangani Majelis Anda (yaitu beri nama yang kuat), buat Login berdasarkan Sertifikat atau Kunci Asimetris tersebut, lalu berikan
-
Jika Anda mencoba mengakses instance SQL Server yang sudah Anda masuki, maka Anda memiliki opsi untuk menggunakan koneksi dalam proses
Context Connection = true;
yang dapat dilakukan dalamSAFE
perakitan. Inilah yang disarankan @Marc dalam jawabannya. Meskipun pasti ada manfaat menggunakan jenis koneksi ini, dan sementara Koneksi Konteks adalah pilihan yang tepat dalam skenario khusus ini, terlalu sederhana dan salah untuk menyatakan bahwa Anda harus selalu menggunakan jenis koneksi ini. Mari kita lihat aspek positif dan negatif dari Koneksi Konteks :- Positif:
- Dapat dilakukan dengan
SAFE
perakitan. - Sangat rendah, jika ada, overhead koneksi karena ini bukan koneksi tambahan.
- Adalah bagian dari sesi saat ini sehingga setiap SQL yang Anda jalankan memiliki akses ke item berbasis sesi seperti tabel sementara lokal dan
CONTEXT_INFO
.
- Dapat dilakukan dengan
-
Negatif:
- Tidak dapat digunakan jika Peniruan Identitas telah diaktifkan.
- Hanya dapat terhubung ke instance SQL Server saat ini.
- Saat digunakan dalam Fungsi (Skalar dan Bernilai Tabel), ia memiliki semua batasan yang sama dengan fungsi T-SQL (misalnya, tidak ada operasi efek samping yang diizinkan) kecuali Anda dapat menjalankan prosedur tersimpan hanya-baca.
- Fungsi Bernilai Tabel tidak diizinkan untuk mengalirkan kembali hasilnya jika mereka membaca kumpulan hasil.
Semua "negatif" ini diizinkan saat menggunakan koneksi reguler/eksternal, meskipun ke instance yang sama dengan tempat Anda mengeksekusi kode ini.
- Positif:
- Jika Anda mencoba mengakses sistem file, membaca dari registri, mendapatkan variabel lingkungan, mengakses jaringan untuk koneksi non-SQL Server (misalnya http, ftp), dll, maka perakitan memerlukan
-
Jika Anda terhubung ke instance tempat Anda mengeksekusi kode ini dan menggunakan koneksi eksternal / reguler, maka tidak perlu menentukan nama Server atau bahkan menggunakan
localhost
. Sintaks yang disukai adalahServer = (local)
yang menggunakan Memori Bersama sedangkan yang lain terkadang menggunakan TCP/IP yang tidak seefisien itu. -
Kecuali Anda memiliki alasan yang sangat spesifik untuk melakukannya, jangan gunakan
Persist Security Info=True;
-
Ini adalah praktik yang baik untuk
Dispose()
dariSqlCommand
. Anda -
Lebih efisien untuk memanggil
insertcommand.Parameters.Add()
tepat sebelumfor
loop, dan kemudian di dalam loop, cukup atur nilainya melaluifirstname.Value =
, yang sudah Anda lakukan, jadi cukup pindahkaninsertcommand.Parameters.Add()
baris tepat sebelumfor
baris. -
tel
/@tel
/listtelnumber
adalahINT
bukannyaVARCHAR
/string
. Nomor telepon, seperti kode pos dan Nomor Jaminan Sosial (SSN), tidak angka, bahkan jika mereka tampak seperti itu.INT
tidak dapat menyimpan0
leading utama s atau sesuatu sepertiex.
untuk menandakan sebuah "ekstensi". -
Semua itu dikatakan, bahkan jika semua hal di atas diperbaiki, masih ada masalah besar dengan kode ini yang harus diatasi :ini adalah operasi yang agak sederhana untuk dilakukan dalam T-SQL langsung, dan melakukan ini dalam SQLCLR terlalu rumit, lebih sulit dan lebih mahal untuk dipelihara, dan jauh lebih lambat. Kode ini melakukan 10.000 transaksi terpisah padahal kode ini dapat dengan mudah dilakukan sebagai kueri berbasis kumpulan tunggal (yaitu satu transaksi). Anda bisa membungkus
for
. Anda loop dalam transaksi yang akan mempercepatnya, tetapi akan selalu lebih lambat daripada pendekatan T-SQL berbasis set karena masih perlu mengeluarkan 10.000INSERT
terpisah pernyataan. Anda dapat dengan mudah mengacak di T-SQL dengan menggunakanNEWID()
atau CRYPT_GEN_RANDOM yang diperkenalkan di SQL Server 2008. (silakan lihat UPDATE bagian di bawah)
Jika Anda ingin mempelajari lebih lanjut tentang SQLCLR, silakan lihat seri yang saya tulis untuk SQL Server Central: Tangga ke SQLCLR (perlu pendaftaran gratis).
PERBARUI
Berikut adalah metode T-SQL murni untuk menghasilkan data acak ini, menggunakan nilai dari Pertanyaan. Sangat mudah untuk menambahkan nilai baru ke salah satu dari 4 variabel tabel (untuk menambah jumlah kemungkinan kombinasi) karena kueri secara dinamis menyesuaikan rentang pengacakan agar sesuai dengan data apa pun yang ada di setiap variabel tabel (yaitu baris 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;
Catatan:
FULL JOIN
s diperlukan alih-alihINNER JOIN
s untuk mendapatkan seluruh@RowsToInsert
jumlah baris.- Baris duplikat dimungkinkan karena sifat pengacakan ini DAN tidak memfilternya dengan menggunakan
DISTINCT
. Namun,DISTINCT
tidak dapat digunakan dengan data sampel yang diberikan dalam pertanyaan karena jumlah elemen dalam setiap variabel array/tabel hanya menyediakan 6300 kombinasi unik dan jumlah baris yang diminta untuk dihasilkan adalah 10.000. Jika lebih banyak nilai ditambahkan ke variabel tabel sehingga total kemungkinan kombinasi unik naik di atas jumlah baris yang diminta, makaDISTINCT
kata kunci dapat ditambahkan kenums
CTE, atau kueri dapat direstrukturisasi menjadiCROSS JOIN
semua variabel tabel, termasukROW_COUNT()
bidang, dan ambilTOP(n)
menggunakanORDER BY NEWID()
. INSERT
dikomentari sehingga lebih mudah untuk melihat bahwa kueri di atas menghasilkan hasil yang diinginkan. Cukup batalkan komentarINSERT
agar kueri melakukan operasi DML yang sebenarnya.