DbContext.Database.ExecuteSqlCommand विधि में पैरामीटर कैसे पास करें?


222

आइए मान लें कि मुझे एंटिटी फ्रेमवर्क में एक sql कमांड को सीधे निष्पादित करने की एक वैध आवश्यकता है। मुझे अपने sql स्टेटमेंट में मापदंडों का उपयोग करने के तरीके का पता लगाने में समस्या हो रही है। निम्न उदाहरण (मेरा वास्तविक उदाहरण नहीं) काम नहीं करता है।

var firstName = "John";
var id = 12;
var sql = @"Update [User] SET FirstName = @FirstName WHERE Id = @Id";
ctx.Database.ExecuteSqlCommand(sql, firstName, id);

ExecuteSqlCommand विधि आपको ADO.Net जैसे नामित मापदंडों में पारित करने की अनुमति नहीं देती है और इस पद्धति के लिए दस्तावेज़ीकरण एक पैरामीटर क्वेरी को निष्पादित करने के तरीके पर कोई उदाहरण नहीं देता है।

मैं मापदंडों को सही ढंग से कैसे निर्दिष्ट करूं?

जवाबों:


295

इसे इस्तेमाल करे:

var sql = @"Update [User] SET FirstName = @FirstName WHERE Id = @Id";

ctx.Database.ExecuteSqlCommand(
    sql,
    new SqlParameter("@FirstName", firstname),
    new SqlParameter("@Id", id));

2
यह वास्तव में सही उत्तर के रूप में होना चाहिए, ऊपर वाला हमलों के लिए प्रवण है और सर्वोत्तम अभ्यास नहीं है।
मिन

8
@Min, स्वीकृत उत्तर इस उत्तर की तुलना में हमलों का अधिक खतरा नहीं है। शायद आपने सोचा था कि यह string.Format का उपयोग कर रहा है - यह नहीं है।
साइमन मैकेंजी

1
इसे उत्तर के रूप में चिह्नित किया जाना चाहिए! यह एक और केवल सही उत्तर है क्योंकि यह डेटाइम के साथ काम करता है।
स्वेन

219

पता चला कि यह काम करता है।

var firstName = "John";
var id = 12;
var sql = "Update [User] SET FirstName = {0} WHERE Id = {1}";
ctx.Database.ExecuteSqlCommand(sql, firstName, id);

13
यह काम करेगा, लेकिन यह तंत्र SQL इंजेक्शन के लिए अनुमति देता है और डेटाबेस को निष्पादन योजना का पुन: उपयोग करने से रोकता है जब बयान फिर से दिखाता है लेकिन विभिन्न मूल्यों के साथ।
ग्रेग बाइल्स 16

95
@GregB मुझे नहीं लगता कि आप यहाँ सही हैं। मैंने परीक्षण किया है कि यह मुझे अनुमति नहीं देगा, उदाहरण के लिए, एक स्ट्रिंग शाब्दिक जल्दी समाप्त। इसके अलावा, मैंने स्रोत कोड को देखा और पाया कि यह DbCommand.CreateParameter का उपयोग करके किसी भी कच्चे मान को पैरामीटर में लपेटता है। तो कोई SQL इंजेक्शन, और एक अच्छा रसीला विधि मंगलाचरण।
जोश गलाघेर

7
@JoshGallagher हाँ, आप सही हैं। मैं एक स्ट्रिंग के बारे में सोच रहा था। परिदृश्य इस एक साथ डाल रहा है।
ग्रेग बाइल्स

6
यह SQL Server 2008 R2 के रूप में काम नहीं करता है। आपके पास दिए गए मापदंडों के बजाय @ p0, @ P2, ..., @pN होगा। SqlParameter("@paramName", value)इसके बजाय उपयोग करें ।
अर्न्थोर

विश्वास नहीं किया जा सकता है कि किसी ने इस क्वेरी के प्रदर्शन प्रभाव का उल्लेख नहीं किया है यदि डेटाबेस तालिका कॉलम ANSI varchar के रूप में निर्दिष्ट किया गया है। .Net स्ट्रिंग्स यूनिकोड हैं जिसका अर्थ है कि पैरामाटर्स सर्वर के लिए नवरचेर के रूप में पारित किए जाएंगे। यह महत्वपूर्ण प्रदर्शन समस्या का कारण होगा क्योंकि डेटा परत को डेटा अनुवाद करना होगा। आपको SqlParameter के दृष्टिकोण के साथ रहना चाहिए और डेटा प्रकार निर्दिष्ट करना चाहिए।
akd

68

आप या तो यह कर सकते हैं:

1) कच्चे तर्क पास करें और {0} वाक्य रचना का उपयोग करें। उदाहरण के लिए:

DbContext.Database.SqlQuery("StoredProcedureName {0}", paramName);

2) DbParameter उपवर्ग तर्क पास करें और @ParamName सिंटैक्स का उपयोग करें।

DbContext.Database.SqlQuery("StoredProcedureName @ParamName", 
                                   new SqlParameter("@ParamName", paramValue);

यदि आप पहले सिंटैक्स का उपयोग करते हैं, तो EF वास्तव में आपके तर्क DbParamater वर्गों के साथ लपेटेगा, उन्हें नाम निर्दिष्ट करेगा, और उत्पन्न पैरामीटर नाम के साथ {0} को प्रतिस्थापित करेगा।

यदि आप एक कारखाने का उपयोग करने की जरूरत नहीं है या (SqlParameter, OracleParamter, आदि) बनाने के लिए DbParamaters का उपयोग करने की जरूरत है क्योंकि पहले वाक्यविन्यास।


6
उल्लिखित है कि {0} वाक्य रचना डेटाबेस अज्ञेय का उल्लेख है। "... आप न ही [sic] एक कारखाने का उपयोग करने की जरूरत है या पता है कि किस प्रकार के DbParamaters [sic] बनाने के लिए ..."
Makotosan

परिदृश्य 1 एक प्रक्षेपित संस्करण के पक्ष में चित्रित किया गया है। समतुल्य अब है: DbContext.Database.ExecuteSqlInterpolated ($ "StoredProcedureName {paramName}");
स्कॉटबी

20

ओरेकल का उपयोग करते समय अन्य उत्तर काम नहीं करते हैं। आपको :इसके बजाय उपयोग करने की आवश्यकता है @

var sql = "Update [User] SET FirstName = :FirstName WHERE Id = :Id";

context.Database.ExecuteSqlCommand(
   sql,
   new OracleParameter(":FirstName", firstName), 
   new OracleParameter(":Id", id));

भगवान का शुक्र है कि कोई भी ओरेकल का उपयोग नहीं करता है। खैर स्वेच्छा से नहीं! संपादित करें: देर मजाक के लिए माफी! संपादित करें: बुरे मजाक के लिए माफी!
क्रिस बॉर्डमैन

18

इसे आज़माएं (संपादित):

ctx.Database.ExecuteSqlCommand(sql, new SqlParameter("FirstName", firstName), 
                                    new SqlParameter("Id", id));

पिछला विचार गलत था।


जब मुझे लगता है कि मुझे निम्न त्रुटि मिलती है: "ऑब्जेक्ट प्रकार से कोई मैपिंग मौजूद नहीं है। System.Data.Objects.ObjectParameter एक ज्ञात प्रबंधित प्रदाता मूल प्रकार के लिए।"
jessegavin

माफ कीजिएगा यह मेरी गलती है। DbParameter का उपयोग करें।
लदिस्लाव मृंका

7
DbParameter अमूर्त है। आपको DbParameter बनाने के लिए SqlParameter का इस्तेमाल करना होगा या DbFactory का इस्तेमाल करना होगा।
jrummell

12

इकाई फ्रेमवर्क कोर 2.0 या इसके बाद के संस्करण के लिए, ऐसा करने का सही तरीका है:

var firstName = "John";
var id = 12;
ctx.Database.ExecuteSqlCommand($"Update [User] SET FirstName = {firstName} WHERE Id = {id}";

ध्यान दें कि एंटिटी फ्रेमवर्क आपके लिए दो मापदंडों का उत्पादन करेगा, इसलिए आप Sql Injection से सुरक्षित हैं।

यह भी ध्यान दें कि यह नहीं है:

var firstName = "John";
var id = 12;
var sql = $"Update [User] SET FirstName = {firstName} WHERE Id = {id}";
ctx.Database.ExecuteSqlCommand(sql);

क्योंकि यह Sql Injection से आपकी रक्षा नहीं करता है, और कोई भी पैरामीटर उत्पन्न नहीं होता है।

इसे और देखें


3
मुझे .NET कोर 2.0 बहुत पसंद है, इससे मुझे खुशी के आंसू मिलते हैं: ')
जोशुआ केमरेर

मैं कुछ लोगों का उत्साह देख सकता हूं क्योंकि .NET कोर 2.0 अब तक मेरे लिए एक शानदार सवारी रही है।
पॉल कार्लटन

एसक्यूएल इंजेक्शन के लिए सबसे पहले कैसे असुरक्षित नहीं है? दोनों सी # स्ट्रिंग इंटरपोलेशन का उपयोग करते हैं। जहां तक ​​मुझे पता है, पहले वाले स्ट्रिंग के विस्तार को पहले से करने में सक्षम नहीं होंगे। मुझे संदेह है कि आपका मतलब हैctx.Database.ExecuteSqlCommand("Update [User] SET FirstName = {firstName} WHERE Id = {id}", firstName, id);
CodeNaked

@CodeNaked, नहीं, मेरा मतलब यह नहीं था। ईएफ मुद्दे से अवगत है, और आपकी सुरक्षा के लिए दो वास्तविक पैरामीटर बनाता है। तो यह केवल एक तार नहीं है जो कि गुजरता है। विवरण के लिए ऊपर लिंक देखें। यदि आप इसे वीएस में आज़माते हैं, तो मेरा संस्करण Sql Injection के बारे में चेतावनी जारी नहीं करेगा, और दूसरा भी करेगा।
ग्रेग गम

1
@GregGum - टीआईएल के बारे में FormattableString। तुम सही हो और यह बहुत अच्छा है!
कोडन्यूड

4

ओरेकल के लिए सरलीकृत संस्करण। यदि आप OracleParameter बनाना नहीं चाहते हैं

var sql = "Update [User] SET FirstName = :p0 WHERE Id = :p1";
context.Database.ExecuteSqlCommand(sql, firstName, id);

2
SQL सर्वर में मैं: p0 के बजाय @ p0 का उपयोग करता हूं।
मारेक मालकविस्की

3
var firstName = "John";
var id = 12;

ctx.Database.ExecuteSqlCommand(@"Update [User] SET FirstName = {0} WHERE Id = {1}"
, new object[]{ firstName, id });

यह इतना आसान है !!!

पैरामीटर संदर्भ जानने के लिए छवि

यहां छवि विवरण दर्ज करें


2

Async Method ("ExecuteSqlCommandAsync") के लिए आप इसे इस तरह से उपयोग कर सकते हैं:

var sql = @"Update [User] SET FirstName = @FirstName WHERE Id = @Id";

await ctx.Database.ExecuteSqlCommandAsync(
    sql,
    parameters: new[]{
        new SqlParameter("@FirstName", firstname),
        new SqlParameter("@Id", id)
    });

यह db-agnostic नहीं है, यह केवल MS-SQL सर्वर के लिए काम करेगा। यह Oracle या PG के लिए फेल हो जाएगा।
एंव्स

1

यदि आपके अंतर्निहित डेटाबेस डेटा प्रकार varchar हैं तो आपको नीचे दिए गए दृष्टिकोण के साथ रहना चाहिए। अन्यथा क्वेरी पर बहुत बड़ा प्रदर्शन प्रभाव पड़ेगा।

var firstName = new SqlParameter("@firstName", System.Data.SqlDbType.VarChar, 20)
                            {
                                Value = "whatever"
                            };

var id = new SqlParameter("@id", System.Data.SqlDbType.Int)
                            {
                                Value = 1
                            };
ctx.Database.ExecuteSqlCommand(@"Update [User] SET FirstName = @firstName WHERE Id = @id"
                               , firstName, id);

अंतर देखने के लिए आप Sql प्रोफाइलर की जांच कर सकते हैं।


0
public static class DbEx {
    public static IEnumerable<T> SqlQueryPrm<T>(this System.Data.Entity.Database database, string sql, object parameters) {
        using (var tmp_cmd = database.Connection.CreateCommand()) {
            var dict = ToDictionary(parameters);
            int i = 0;
            var arr = new object[dict.Count];
            foreach (var one_kvp in dict) {
                var param = tmp_cmd.CreateParameter();
                param.ParameterName = one_kvp.Key;
                if (one_kvp.Value == null) {
                    param.Value = DBNull.Value;
                } else {
                    param.Value = one_kvp.Value;
                }
                arr[i] = param;
                i++;
            }
            return database.SqlQuery<T>(sql, arr);
        }
    }
    private static IDictionary<string, object> ToDictionary(object data) {
        var attr = System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance;
        var dict = new Dictionary<string, object>();
        foreach (var property in data.GetType().GetProperties(attr)) {
            if (property.CanRead) {
                dict.Add(property.Name, property.GetValue(data, null));
            }
        }
        return dict;
    }
}

उपयोग:

var names = db.Database.SqlQueryPrm<string>("select name from position_category where id_key=@id_key", new { id_key = "mgr" }).ToList();

7
कोई भी मौका आप इस कोड को समझा सकते हैं और यह प्रश्न का उत्तर क्यों है, ताकि बाद में जो लोग इसे ढूंढते हैं, वे इसे समझ सकें?
एंड्रयू बार्बर

1
{0} सिंटैक्स के साथ समस्या जो आप पठनीयता को ढीला करते हैं - मैं व्यक्तिगत रूप से इसे पसंद नहीं करता। SqlParameters पास करने में समस्या जो आपको DbParameter (SqlParameter, OracleParameter आदि) के ठोस कार्यान्वयन को निर्दिष्ट करने की आवश्यकता है। प्रदान किया गया उदाहरण आपको इन मुद्दों से बचने की अनुमति देता है।
नेको

3
मुझे लगता है कि यह एक मान्य राय है, लेकिन आपने वास्तव में यहां पूछे जा रहे सवाल का जवाब नहीं दिया है; ExecuteSqlCommand()आप पैरामीटर कैसे पास करते हैं, जब आप उत्तर पोस्ट करते हैं तो पूछे जाने वाले विशिष्ट प्रश्न का उत्तर देना सुनिश्चित करें।
एंड्रयू बार्बर

3
नीचा दिखाया गया है क्योंकि यह अनावश्यक रूप से जटिल है (जैसे कि प्रतिबिंब का उपयोग करता है, पहिया का फिर से आविष्कार, विभिन्न डेटाबेस प्रदाताओं के लिए खाते में विफल रहता है)
एक phu

मतदान हुआ क्योंकि यह संभावित समाधानों में से एक को दर्शाता है। मुझे यकीन है कि ExecuteSqlCommand मापदंडों को उसी तरह स्वीकार करता है जिस तरह SqlQuery करता है। मैं मापदंडों को पास करने की Dapper.net शैली को भी पसंद करता हूं।
ज़ार शारदान

0

एक संग्रहीत कार्यविधि में एकाधिक params कि vb में कई params है:

Dim result= db.Database.ExecuteSqlCommand("StoredProcedureName @a,@b,@c,@d,@e", a, b, c, d, e)

0

संग्रहीत प्रक्रियाओं को नीचे की तरह निष्पादित किया जा सकता है

 string cmd = Constants.StoredProcs.usp_AddRoles.ToString() + " @userId, @roleIdList";
                        int result = db.Database
                                       .ExecuteSqlCommand
                                       (
                                          cmd,
                                           new SqlParameter("@userId", userId),
                                           new SqlParameter("@roleIdList", roleId)
                                       );

System.Data.SqlClient
फ्लाइंग वी

0

.NET कोर 2.2 के लिए, आप FormattableStringगतिशील SQL के लिए उपयोग कर सकते हैं ।

//Assuming this is your dynamic value and this not coming from user input
var tableName = "LogTable"; 
// let's say target date is coming from user input
var targetDate = DateTime.Now.Date.AddDays(-30);
var param = new SqlParameter("@targetDate", targetDate);  
var sql = string.Format("Delete From {0} Where CreatedDate < @targetDate", tableName);
var froamttedSql = FormattableStringFactory.Create(sql, param);
_db.Database.ExecuteSqlCommand(froamttedSql);

System.Data.SqlClient
फ्लाइंग वी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.