2008-10-03 10 views
9

वेब अनुप्रयोग के लिए मेरी कक्षाओं में से एक में मैं विकास कर रहा हूं, मेरे पास कुछ उचित लंबे SQL प्रश्न हैं।एसक्यूएल कमांड के लिए कोड पठनीयता में सुधार

तीन-स्तरीय अनुप्रयोग विकसित करते समय, इस तरह के कोड कोटर बनाने के लिए सर्वोत्तम प्रथाएं क्या हैं?

Dim dc As New SqlCommand("INSERT INTO Choices VALUES ('" + _ 
           SanitizeInput(strUser) + "', '" + _ 
           SanitizeInput(strFirstHalfDay) + "', '" + _ 
           SanitizeInput(strSecondHalfDay) + "', '" + _ 
           SanitizeInput(strFullDay) + "', " + _ 
           SanitizeInput(Convert.ToInt32(firstHalfPaid).ToString()) + ", " + _ 
           SanitizeInput(Convert.ToInt32(secondHalfPaid).ToString()) + ", " + _ 
           SanitizeInput(Convert.ToInt32(fullPaid).ToString()) + ")", cn) 

आप कोड के इस प्रकार स्वीकार्य या बदबूदार पर विचार करते हैं?

उत्तर

34

स्टॉप, ऐसा न करें, तैयार स्टैमेंट का उपयोग करें, आपको सुरक्षा और पठनीयता मिल जाएगी।

उपयोग इस बजाय:

Dim dc As New SqlCommand("INSERT INTO Choices VALUES (@User, @FirstHalfDay, @SecondHalfDay, @FullDay, @FirstHalfPaid, @SecondHalfPaid, @FullPaid'", cn) 
dc.Parameters.Add (new SqlParameter ("User", strUser)) 
dc.Parameters.Add (new SqlParameter ("FirstHalfDay", strFirstHalfDay)) 
dc.Parameters.Add (new SqlParameter ("SecondHalfDay", strSecondHalfDay)) 
dc.Parameters.Add (new SqlParameter ("FullDay", strFullDay)) 
dc.Parameters.Add (new SqlParameter ("FirstHalfPaid", firstHalfPaid)) 
dc.Parameters.Add (new SqlParameter ("SecondHalfPaid", secondHalfPaid)) 
dc.Parameters.Add (new SqlParameter ("FullPaid", fullPaid)) 
+0

बहुत बहुत धन्यवाद। क्या यह एसक्यूएल इंजेक्शन और एक्सएसएस को रोक देगा? – RodgerB

+0

यह एसक्यूएल इंजेक्शन को रोक देगा लेकिन कोई एक्सएसएस नहीं होगा, इसलिए आपके sanitize फ़ंक्शन को एक्सएसएस की तलाश करनी चाहिए लेकिन एसक्यूएल इंजेक्शन के लिए नहीं। – albertein

+0

गुम मिलान मिलान) – Josh

1

बदबूदार - कि SanitizeInput लगभग निश्चित रूप से एसक्यूएल इंजेक्शन की चपेट में है।

मैं एक .NET wrapper (डीबी स्कीमा से उत्पन्न) के साथ, एक पैरामीटर एसपी (डीबी स्कीमा से उत्पन्न कोड, संभवतः बाद में हाथ से tweaked) का उपयोग करेंगे। की है कि सी में #

+0

मैंने बनाए गए SanitizeInput फ़ंक्शन को SQL इंजेक्शन और एक्सएसएस को रोक दिया है। – RodgerB

+0

बहुत बढ़िया, कोड पोस्ट करें। –

+0

आप SQL इंजेक्शन मूल रूप से sanitazing – albertein

-1

प्रत्यक्ष पुनर्लेखन होगा:

SqlCommand dc = new SqlCommand(String.Format(@" 
    INSERT INTO Choices VALUES ('{0}', '{1}', '{2}', {3}, {4}, {5}) 
", SanitizeInput(strUser), SanitizeInput(strFirstHalfDay), SanitizeInput(strFullDay), SanitizeInput(Convert.ToInt32(firstHalfPaid).ToString()), SanitizeInput(Convert.ToInt32(secondHalfPaid).ToString()), SanitizeInput(Convert.ToInt32(fullPaid).ToString())), cn); 

मैं स्ट्रिंग संयोजन के बजाय एक बहुत String.Format का उपयोग करें। यह पठनीयता भी सुधारता है। मैं वीबी से परिचित नहीं हूं, क्षमा करें।

मैं मानता हूं कि पैरामीटर का उपयोग करना एक बेहतर समाधान है।

+0

एसक्यूएल इंजेक्शन जावा के लिए – albertein

0

आप हाइबरनेट जैसे किसी तृतीय पक्ष डेटा अबास्ट्रक्शन का उपयोग कर सकते हैं (जावा पर - मुझे नहीं पता कि .NET के लिए क्या उपलब्ध है)।

या आप अपने स्वयं के सहायक वर्गों है कि वाक्य रचना की तरह की अनुमति देने के लिख सकते हैं:

Dim insHelper As New InsertionHelper(conn, "Choices"); 

insHelper.appendValue(strUser); 
insHelper.appendValue(strFirstHalfDay); 
insHelper.appendValue(strSecondHalfDay); 
insHelper.appendValue(strFullDay); 
insHelper.appendValue(firstHalfPaid); // overloaded for different data types 
insHelper.appendValue(secondHalfPaid); 
insHelper.appendValue(fullPaid); 

insHelper.execute(); 

तुम भी विधि मिश्रण करने के लिए चेनिंग जोड़ सकते हैं:

Dim insHelperAs New InsertionHelper(conn, "Choices"); 

insHelper 
    .appendValue(strUser) 
    .appendValue(strFirstHalfDay) 
    .appendValue(strSecondHalfDay) 
    .appendValue(strFullDay) 
    .appendValue(firstHalfPaid) 
    .appendValue(secondHalfPaid) 
    .appendValue(fullPaid) 
    .execute(); 
+0

हाइबरनेट साथ एक संभावित खतरा है कि - नेट के लिए> NHibernate। – yfeldblum

0

यह दृष्टिकोण एक छोटी परियोजना के लिए ठीक है, हालांकि महत्वपूर्ण आकार के किसी भी चीज़ के लिए आपको अपने प्रश्नों का निर्माण करने या अपना खुद का विकास करने के लिए किसी तृतीय पक्ष लाइब्रेरी पर विचार करना चाहिए।

सामान्य पद्धति का उपयोग मैं कुछ इस तरह चला जाता है: (। मैं जावा सिंटैक्स का उपयोग कर रहा हूँ मैं क्या सबसे करने के लिए इस्तेमाल कर रहा हूँ, क्योंकि है कि)

क्वेरी खाका गुण फ़ाइल

some.query=INSERT INTO Choices VALUES ('{0}', '{1}', '{2}', '{3}') 

फ्रेमवर्क कोड

public class SqlUtil { 

    static Properties queries; 
    static { 
     queries = <LOAD QUERY PROPS> 
    } 

    public static SqlCommand createCommand(String propName, Object params ...) 
     throws SqlException 
    { 
     String cmd = queries.getString(propName) 

     if (propName == null || "".equals(propName)) 
      throw new SqlException("Query not found"); 

     int i=0; 
     for (Object param : params) { 
      cmd = cmd.replace("{" + i + "}", param) 
      i++; 
     } 

     return new SqlCommand(cmd); 
    } 

} 

प्रयोग कोड:

SqlCommand dc = SqlUtil.createCommand("some.query", SanitizeInput(strUser), SanitizeInput(strFirstHalfDay)) 
4

मैं इसे अधिक पठनीय और सुरक्षित होने पर विचार करता हूं i.e.कम SQL इंजेक्शन से ग्रस्त:

Dim dc As New SqlCommand("INSERT INTO Choices VALUES (@UserName, @FirstHalfDay, @SecondHalfDay, @FullDay, @FirstHalfPaid, @SecondHalfPaid, @FullPaid)", cn) 

dc.Parameters.AddWithValue("@UserName", strUsername) 
dc.Parameters.AddWithValue("@FirstHalfDay", strFirstHalfDay) 
dc.Parameters.AddWithValue("@SecondHalfDay", strSecondHalfDay) 
dc.Parameters.AddWithValue("@FullDay", strFullDay) 
dc.Parameters.AddWithValue("@FirstHalfPaid", Convert.ToInt32(firstHalfPaid)) 
dc.Parameters.AddWithValue("@SecondHalfPaid", Convert.ToInt32(secondHalfPaid)) 
dc.Parameters.AddWithValue("@FullPaid", Convert.ToInt32(fullPaid)) 

चुनिंदा बयानों के लिए आप ऐसा करते समय आप एसक्यूएल सर्वर जो के रूप में यह एक ही स्ट्रिंग सिर्फ paramterised हो जाएगा क्वेरी योजना कैश करने के लिए सक्षम हो जाएगा उपयोग कर रहे हैं अतिरिक्त लाभ मिल जाएगा। यदि आप SQL सर्वर का उपयोग नहीं कर रहे हैं तो मामूली परिवर्तन की आवश्यकता हो सकती है। आपको मुफ्त में एक और लाभ भी मिलता है जो कम स्ट्रिंग कॉन्सटेनेशन के माध्यम से थोड़ा बेहतर प्रदर्शन करता है।

मैं व्यक्तिगत रूप से विकल्प तालिका नाम के बाद कॉलम जोड़ता हूं जो डेटाबेस तालिका में नए कॉलम जोड़ते समय ब्रेकेज से कम प्रवण होता है (डिफ़ॉल्ट मान मानते हैं)।

2

जबकि मुझे लगता है कि अपने कोड अद्भुत है, मैं संभावित सुधार की एक संक्षिप्त सूची है:

  • आप एसक्यूएल एक मानचित्रण तकनीक का उपयोग लेखन के बजाय कर रहे हैं (NHibernate, LINQ एसक्यूएल के लिए, एफई, सबसोनिक, एलएलबीएलजीनप्रो, इत्यादि)
  • अनुमोदित है कि आप एसक्यूएल लिख रहे हैं, आप पैरामीटर का उपयोग नहीं कर रहे हैं। कम से कम आप इनपुट को सही ढंग से संचरित कर रहे हैं क्योंकि आप स्ट्रिंग-कॉन्सटेनेशन करते हैं ... उम्मीद है ....
  • अनुमोदित है कि आप बिना पैरामीटर के एसक्यूएल लिख रहे हैं, आप स्ट्रिंग-फ़र्मेट का उपयोग नहीं कर रहे हैं ताकि आपकी स्ट्रिंग-बिल्डिंग और स्ट्रिंग- स्वरूपण।
  • आपके परिवर्तनीय नाम गन्दा हैं। आप अपने चर को हंगेरियन नोटेशन सम्मेलन के साथ नाम दे रहे हैं। हंगेरियन नोटेशन मूल रूप से आपके परिवर्तनीय नामों की सहायता करने के उद्देश्य से व्यक्त करता है कि इन चरों को का उपयोग कैसे किया जाता है, उनके प्रकारों को व्यक्त नहीं किया जाता है।
  • आप कार्यान्वयन के लिए कोडिंग कर रहे हैं, इंटरफ़ेस नहीं। आपके कनेक्शन वैरिएबल को टाइप किया जाना चाहिए IDbConnection और आपके कमांड वैरिएबल को टाइप किया जाना चाहिए IDbCommand। SqlConnection और SqlCommand नहीं है। IDbConnection.CreateCommand() का उपयोग करें।
  • SanitizeInput का नाम बदलाStringForSQL या कुछ ऐसा होना चाहिए जो इसके वास्तविक इरादे को इंगित करता है। आपको संख्याओं से बचने की जरूरत नहीं है।
0

कन्स्ट्रक्टर को कॉल करने से पहले एसक्यूएल कमांड को एक अलग स्ट्रिंग बनाएं। इसे पढ़ना आसान होगा।

बजाय:

Dim dc As New SqlCommand("INSERT INTO SomeTable....", 
         Arg(blah blah blah)) 

यह करें:

Dim sqlstr = 
"INSERT INTO SomeTable...." 

Dim dc As New SqlCommand(sqlstr, Arg(blah blah blah)) 

(माफ कर दो मेरी सही वीबी वाक्य रचना नहीं जानते हुए भी)

बात यह है कि SqlCommand में शाब्दिक स्ट्रिंग डालने का कार्य () कन्स्ट्रक्टर सिर्फ एक बड़ी कमांड में बहुत सारी चीजें क्रैम कर रहा है जिसे किसी को बाद में उसके सिर में अलग करना पड़ता है।

इसके अलावा, जब आप एसक्यूएल आप जबकि डिबगिंग को क्रियान्वित कर रहे हैं बाहर प्रिंट करना चाहते हैं, यह एक साधारण

Print "Now executing: " + sqlstr 

में फेंक चिंता मत करो कि तुम एक "अतिरिक्त" बना रहे हैं बहुत आसान हो जाएगा चर। कंप्यूटर पर कोई फर्क नहीं पड़ता।

संबंधित मुद्दे