इस कोड में कई मुद्दे चल रहे हैं जिन्हें संबोधित करने की आवश्यकता है:
-
बताए गए प्रश्न के संबंध में, जब आपको System.Security.SecurityException . मिलता है त्रुटि, जो उस कोड को संदर्भित करता है जो डेटाबेस के बाहर पहुंचने की कोशिश कर रहा है, कुछ ऐसा जिसकी
SAFE
में अनुमति नहीं है सभा। आप इसे कैसे ठीक करते हैं यह इस बात पर निर्भर करता है कि आप क्या हासिल करने की कोशिश कर रहे हैं।- यदि आप फ़ाइल सिस्टम तक पहुँचने का प्रयास कर रहे हैं, रजिस्ट्री से पढ़ें, एक पर्यावरण चर प्राप्त करें, एक गैर-एसक्यूएल सर्वर कनेक्शन (जैसे http, ftp), आदि के लिए नेटवर्क का उपयोग करें, तो असेंबली को एक
PERMISSION_SET
काEXTERNAL_ACCESS
. अपनी असेंबली कोSAFE
. के अलावा किसी और चीज़ पर सेट करने के लिए , आपको या तो चाहिए:- उसी कुंजी के आधार पर एक प्रमाणपत्र या असममित कुंजी बनाएं जिसका उपयोग आपने अपनी असेंबली पर हस्ताक्षर करने के लिए किया था (यानी इसे एक मजबूत नाम दें), उस प्रमाणपत्र या असममित कुंजी के आधार पर एक लॉगिन बनाएं, और फिर
EXTERNAL ACCESS ASSEMBLY
उस लॉगिन की अनुमति। यह विधि काफी है अन्य विधि पर पसंद किया जाता है, जो है: - असेंबली वाले डेटाबेस को
TRUSTWORTHY ON
पर सेट करें . इस पद्धति का उपयोग केवल अंतिम उपाय के रूप में ही किया जाना चाहिए यदि विधानसभा पर हस्ताक्षर करना संभव नहीं है। या त्वरित परीक्षण उद्देश्यों के लिए। डेटाबेस कोTRUSTWORTHY ON
. पर सेट करना संभावित सुरक्षा खतरों के लिए आपका उदाहरण खोलता है और इससे बचा जाना चाहिए, भले ही अन्य विधि की तुलना में तेज़/आसान हो।
- उसी कुंजी के आधार पर एक प्रमाणपत्र या असममित कुंजी बनाएं जिसका उपयोग आपने अपनी असेंबली पर हस्ताक्षर करने के लिए किया था (यानी इसे एक मजबूत नाम दें), उस प्रमाणपत्र या असममित कुंजी के आधार पर एक लॉगिन बनाएं, और फिर
-
यदि आप SQL सर्वर इंस्टेंस तक पहुँचने का प्रयास कर रहे हैं जिसमें आप पहले से लॉग इन हैं, तो आपके पास
Context Connection = true;
के इन-प्रोसेस कनेक्शन का उपयोग करने का विकल्प है। जो एकSAFE
. में किया जा सकता है सभा। @Marc ने अपने उत्तर में यही सुझाव दिया है। हालांकि इस प्रकार के कनेक्शन का उपयोग करने के लिए निश्चित रूप से लाभ हैं, और जबकि संदर्भ कनेक्शन इस विशेष परिदृश्य में उपयुक्त विकल्प था, यह कहना अति-सरल और गलत है कि आपको हमेशा करना चाहिए इस प्रकार के कनेक्शन का उपयोग करें। आइए संदर्भ कनेक्शन . के सकारात्मक और नकारात्मक पहलुओं को देखें :- सकारात्मक:
SAFE
में किया जा सकता है विधानसभा।- बहुत कम, यदि कोई हो, कनेक्शन ओवरहेड क्योंकि यह कोई अतिरिक्त कनेक्शन नहीं है।
- वर्तमान सत्र का हिस्सा है इसलिए आपके द्वारा निष्पादित किसी भी SQL के पास स्थानीय अस्थायी तालिकाओं और
CONTEXT_INFO
जैसे सत्र-आधारित आइटम तक पहुंच है। ।
-
नकारात्मक:
- यदि प्रतिरूपण सक्षम किया गया है तो इसका उपयोग नहीं किया जा सकता।
- केवल वर्तमान SQL सर्वर इंस्टेंस से कनेक्ट हो सकता है।
- फ़ंक्शंस (स्केलर और टेबल-वैल्यूड) में उपयोग किए जाने पर इसमें टी-एसक्यूएल फ़ंक्शंस के समान सभी प्रतिबंध होते हैं (उदाहरण के लिए कोई साइड-इफेक्टिंग ऑपरेशन की अनुमति नहीं है) सिवाय इसके कि आप केवल-पढ़ने के लिए संग्रहीत प्रक्रियाओं को निष्पादित कर सकते हैं।
- तालिका-मूल्यवान फ़ंक्शंस को परिणाम सेट पढ़ने पर अपने परिणामों को वापस स्ट्रीम करने की अनुमति नहीं है।
नियमित / बाहरी कनेक्शन का उपयोग करते समय इन सभी "नकारात्मक" की अनुमति है, भले ही यह उसी उदाहरण के लिए हो जिससे आप इस कोड को निष्पादित कर रहे हैं।
- सकारात्मक:
- यदि आप फ़ाइल सिस्टम तक पहुँचने का प्रयास कर रहे हैं, रजिस्ट्री से पढ़ें, एक पर्यावरण चर प्राप्त करें, एक गैर-एसक्यूएल सर्वर कनेक्शन (जैसे http, ftp), आदि के लिए नेटवर्क का उपयोग करें, तो असेंबली को एक
-
यदि आप इस उदाहरण से कनेक्ट कर रहे हैं कि आप बाहरी / नियमित कनेक्शन से इस कोड को निष्पादित कर रहे हैं, तो सर्वर का नाम निर्दिष्ट करने या यहां तक कि
localhost
का उपयोग करने की कोई आवश्यकता नहीं है। . पसंदीदा सिंटैक्स हैServer = (local)
जो साझा मेमोरी का उपयोग करता है जबकि अन्य कभी-कभी टीसीपी/आईपी का उपयोग कर सकते हैं जो उतना कुशल नहीं है। -
जब तक आपके पास ऐसा करने का कोई विशेष कारण न हो,
Persist Security Info=True;
का उपयोग न करें -
Dispose()
. करना एक अच्छा अभ्यास है आपकेSqlCommand
. का -
insertcommand.Parameters.Add()
. को कॉल करना अधिक कुशल हैfor
. के ठीक पहले लूप, और फिर लूप के अंदर, बसfirstname.Value =
. के माध्यम से मान सेट करें , जो आप पहले से कर रहे हैं, तो बसinsertcommand.Parameters.Add()
ले जाएँfor
. के ठीक पहले की पंक्तियाँ लाइन। -
tel
/@tel
/listtelnumber
INT
हैंVARCHAR
. के बजाय /string
. ज़िप कोड और सामाजिक सुरक्षा नंबर (SSN) की तरह ही टेलीफ़ोन नंबर नहीं हैं संख्याएँ, भले ही वे प्रतीत हों।INT
अग्रणी0
को स्टोर नहीं कर सकता s या ऐसा कुछex.
एक "एक्सटेंशन" को दर्शाने के लिए। -
यह सब कहा जा रहा है, भले ही उपरोक्त सभी को ठीक कर लिया गया हो, फिर भी इस कोड के साथ एक बड़ी समस्या है जिसे संबोधित किया जाना चाहिए :यह सीधे टी-एसक्यूएल में प्रदर्शन करने के लिए एक अपेक्षाकृत सरल ऑपरेशन है, और एसक्यूएलसीएलआर में ऐसा करना अधिक जटिल, कठिन और बनाए रखने के लिए अधिक महंगा है, और बहुत धीमा है। यह कोड 10,000 अलग-अलग लेनदेन कर रहा है, जबकि इसे एक सेट-आधारित क्वेरी (यानी एक लेनदेन) के रूप में आसानी से किया जा सकता है। आप अपना
for
. लपेट सकते हैं एक लेन-देन में लूप जो इसे गति देगा, लेकिन यह अभी भी सेट-आधारित टी-एसक्यूएल दृष्टिकोण से हमेशा धीमा रहेगा क्योंकि इसे अभी भी 10,000 अलगINSERT
जारी करने की आवश्यकता है बयान। आपNEWID()
. का उपयोग करके आसानी से T-SQL में रैंडमाइज़ कर सकते हैं या CRYPT_GEN_RANDOM जिसे SQL Server 2008 में पेश किया गया था। (कृपया अद्यतन करें . देखें) नीचे अनुभाग)
यदि आप SQLCLR के बारे में अधिक जानना चाहते हैं, तो कृपया उस श्रृंखला को देखें जो मैं SQL सर्वर सेंट्रल के लिए लिख रहा हूँ: SQLCLR की सीढ़ी (निःशुल्क पंजीकरण आवश्यक)।
अपडेट करें
प्रश्न से मूल्यों का उपयोग करके, इस यादृच्छिक डेटा को उत्पन्न करने की एक शुद्ध टी-एसक्यूएल विधि यहां दी गई है। 4 तालिका चरों में से किसी में भी नए मान जोड़ना आसान है (संभावित संयोजनों की संख्या बढ़ाने के लिए) क्योंकि क्वेरी प्रत्येक तालिका चर (यानी पंक्तियों 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;
नोट:
FULL JOIN
INNER JOIN
. के बजाय s की आवश्यकता है s संपूर्ण@RowsToInsert
get प्राप्त करने के लिए पंक्तियों की मात्रा।- इस यादृच्छिकरण की प्रकृति के कारण डुप्लिकेट पंक्तियां संभव हैं और
DISTINCT
का उपयोग करके उन्हें फ़िल्टर नहीं कर रहे हैं . हालांकि,DISTINCT
प्रश्न में दिए गए नमूना डेटा के साथ उपयोग नहीं किया जा सकता है क्योंकि प्रत्येक सरणी/तालिका चर में तत्वों की संख्या केवल 6300 अद्वितीय संयोजन प्रदान करती है और उत्पन्न करने के लिए पंक्तियों की अनुरोधित संख्या 10,000 है। यदि तालिका चर में अधिक मान जोड़े जाते हैं जैसे कि कुल संभव अद्वितीय संयोजन अनुरोधित पंक्तियों की संख्या से ऊपर उठ जाते हैं, तो या तोDISTINCT
कीवर्ड कोnums
. में जोड़ा जा सकता है CTE, या क्वेरी को केवलCROSS JOIN
. में पुनर्गठित किया जा सकता है सभी तालिका चर, एकROW_COUNT()
include शामिल करें फ़ील्ड, औरTOP(n)
. को पकड़ेंORDER BY NEWID()
. का उपयोग करके । INSERT
टिप्पणी की गई है, इसलिए यह देखना आसान है कि ऊपर दी गई क्वेरी वांछित परिणाम उत्पन्न करती है। बसINSERT
को अनकम्मेंट करें क्वेरी को वास्तविक डीएमएल ऑपरेशन करने के लिए।