วิธีการใช้ DbContext.Database.SqlQuery <TElement> (sql, params) กับโพรซีเดอร์ที่เก็บไว้? รหัส EF แรก CTP5


250

ฉันมีกระบวนงานที่เก็บไว้ซึ่งมีพารามิเตอร์สามตัวและฉันได้ลองใช้วิธีการต่อไปนี้เพื่อส่งคืนผลลัพธ์:

context.Database.SqlQuery<myEntityType>("mySpName", param1, param2, param3);

ตอนแรกฉันพยายามใช้SqlParameterวัตถุเป็น params แต่มันใช้งานไม่ได้และขว้างSqlExceptionด้วยข้อความต่อไปนี้:

ขั้นตอนหรือฟังก์ชัน 'mySpName' คาดว่าพารามิเตอร์ '@ param1' ซึ่งไม่ได้ให้มา

ดังนั้นคำถามของฉันคือคุณสามารถใช้วิธีนี้กับโพรซีเดอร์ที่เก็บซึ่งคาดว่าพารามิเตอร์ได้อย่างไร

ขอบคุณ


คุณใช้ SQL Server เวอร์ชันใดอยู่ ฉันมีปัญหากับรหัสที่ทำงานในปี 2008 ในโหมด compat (90) แต่เมื่อฉันเรียกใช้เทียบกับปี 2005 มันล้มเหลวด้วยข้อผิดพลาดทางไวยากรณ์
Gats

4
@Gats - ฉันมีปัญหาเดียวกันกับ SQL 2005 เพิ่ม "EXEC" ก่อนชื่อกระบวนงานที่เก็บไว้ ฉันโพสต์ข้อมูลนี้ที่นี่เพื่อใช้อ้างอิงในอนาคต: stackoverflow.com/questions/6403930/…
Dan Mork

คำตอบ:


389

คุณควรระบุอินสแตนซ์ SqlParameter ด้วยวิธีต่อไปนี้:

context.Database.SqlQuery<myEntityType>(
    "mySpName @param1, @param2, @param3",
    new SqlParameter("param1", param1),
    new SqlParameter("param2", param2),
    new SqlParameter("param3", param3)
);

3
คุณจะทำให้วิธีนี้ทำงานกับประเภท nullable ได้อย่างไร ฉันพยายามนี้ด้วยทศนิยม nullable แต่เมื่อทศนิยมเป็นโมฆะฉันได้รับข้อผิดพลาดว่าพารามิเตอร์หายไป อย่างไรก็ตามวิธีการดังกล่าวข้างล่างโดย @DanMork ทำงานค้นหา
พอลจอห์นสัน

2
การส่งDbNull.Valueแทนโมฆะสามารถแก้ปัญหาได้หรือไม่
Alireza

29
นอกจากนี้คุณยังสามารถใช้ \ @ p # ไวยากรณ์เพื่อหลีกเลี่ยงการใช้ SqlParameter เช่นเดียวกับในบริบทฐานข้อมูล. sqlQuery <myEntityType ("mySpName \ @ p0, \ @ p1, \ @ p2", param1, param2, param3) ที่มา: msdn.microsoft.com/en-US/data/jj592907 (หมายเหตุ: ต้องใช้ \ @ เพื่อหลีกเลี่ยงการแจ้งเตือนผู้ใช้ควรอ่านโดยไม่ใช้แบ็กสแลช)
Marco

3
หากคุณใช้พารามิเตอร์ DateTime คุณจะต้องระบุประเภทพารามิเตอร์ด้วยไม่ใช่เฉพาะชื่อและค่า ตัวอย่างเช่น: dbContext.Database.SqlQuery <Invoice> ("spGetInvoices @dateFrom, @dateTo", ใหม่ SqlParameter {ParameterName = "dateFrom", SqlDbType = SqlDbType.DateTime, Value = startDate}, SqlParameter ใหม่ SqlDbType = SqlDbType.DateTime, Value = endDate}); อีกสิ่งที่สำคัญคือการเคารพในลำดับของพารามิเตอร์
Francisco Goldenstein

คุณช่วยกรุณาตรวจสอบสิ่งที่ฉันทำผิดฉันได้ติดตามคุณ guidline แต่ไม่มีผลกระทบใด ๆ เลยที่stackoverflow.com/questions/27926598/…
พิษ

129

นอกจากนี้คุณสามารถใช้พารามิเตอร์ "sql" เป็นตัวระบุรูปแบบ:

context.Database.SqlQuery<MyEntityType>("mySpName @param1 = {0}", param1)

ต้องขึ้นคะแนนนี้ ในขณะที่มันไม่ได้รับการยอมรับว่าเป็นคำตอบมันง่ายกว่ามากในการเขียนวิธีแก้ปัญหากว่าที่เลือกไว้เป็นคำตอบ
Nikkoli

10
ไวยากรณ์นี้เกี่ยวกับฉันเล็กน้อย มันจะไวต่อการฉีด SQL หรือไม่ ฉันคิดว่า EF กำลังใช้งาน "EXEC mySpName @ Param1 =" และเป็นไปได้ไหมที่จะส่ง "x 'GO [สคริปต์ที่เป็นอันตราย]" และทำให้เกิดปัญหา
Tom Halladay

10
@ TomHalladay ไม่มีความเสี่ยงของการฉีด SQL - วิธีการจะยังคงพูดและหนีพารามิเตอร์ตามประเภทของพวกเขาเช่นเดียวกับพารามิเตอร์ @ สไตล์ ดังนั้นสำหรับพารามิเตอร์สตริงคุณจะต้องใช้ "SELECT * FROM Users WHERE email = {0}" โดยไม่มีเครื่องหมายอัญประกาศในคำสั่งของคุณ
Ross McNab

ในกรณีของฉันเรามีพารามิเตอร์ทางเลือกมากมายสำหรับ SP และไม่สามารถใช้งานกับ SqlParameters ได้ แต่รูปแบบนี้ใช้กลอุบายเพียงแค่เพิ่ม 'EXEC' ในตอนแรก ขอบคุณ
Onur Topal

1
คำตอบนี้มีประโยชน์หากคุณต้องระบุพารามิเตอร์ให้กับ proc ด้วยพารามิเตอร์ทางเลือก ตัวอย่างที่ใช้งานไม่ได้: ProcName @optionalParam1 = @opVal1, @optionalParam2 = @opVal2 ตัวอย่างที่ใช้งานได้:ProcName @optionalParam1 = {0}, @optionalParam2 = {1}
Garrison Neely

72

โซลูชันนี้มีไว้สำหรับ SQL Server 2005 เท่านั้น

พวกคุณเป็นผู้ช่วยชีวิต แต่ในขณะที่ @Dan Mork พูดว่าคุณต้องเพิ่ม EXEC ลงในส่วนผสม สิ่งที่ทำให้ฉันสะดุดคือ:

  • 'EXEC' หน้าชื่อ Proc
  • เครื่องหมายจุลภาคในระหว่าง Params
  • การตัด '@' บนคำจำกัดความของพารามิเตอร์ (ไม่แน่ใจว่าจำเป็นต้องใช้บิต)

:

context.Database.SqlQuery<EntityType>(
    "EXEC ProcName @param1, @param2", 
    new SqlParameter("param1", param1), 
    new SqlParameter("param2", param2)
);

21
+1 คำตอบที่ได้รับการโหวตอย่างใดอย่างหนึ่งไม่รวมถึงexecแต่ฉันสามารถยืนยันได้ว่าฉันได้รับข้อยกเว้นถ้าฉันไม่ได้ระบุ
Jordan Gray

ขอบคุณฉันได้รับข้อผิดพลาดเพิ่ม EXEC และข้อผิดพลาดหายไป ส่วนที่แปลกคือถ้าฉันทำ context.Database.SqlQuery <EntityType> ("ProcName '" + param1 + "', '" + param2 + "'"); มันใช้งานได้ แต่ถ้าฉันเพิ่มพารามิเตอร์มันไม่ทำงานจนกว่าฉันจะเพิ่มคำหลัก EXEC
Solmead

2
FYI: ฉันไม่ต้องการexecคำหลัก +1 สำหรับการลบ @ บน params ที่ทำให้ฉันยุ่งเสมอ
นาธานคูป

+1, ฉันพลาด EXEC และได้รับ SqlExceptions พร้อมข้อความ: ไวยากรณ์ไม่ถูกต้องใกล้กับ 'procName'
A. Murray

1
@ Ziggler คุณอยู่ในปี 2005 หรือใหม่กว่า คำหลักของ EXEC นั้นเป็นปัญหาสำหรับพวกเราในปี 2005
Tom Halladay

15
return context.Database.SqlQuery<myEntityType>("mySpName {0}, {1}, {2}",
new object[] { param1, param2, param3 });

//หรือ

using(var context = new MyDataContext())
{
return context.Database.SqlQuery<myEntityType>("mySpName {0}, {1}, {2}",
new object[] { param1, param2, param3 }).ToList();
}

//หรือ

using(var context = new MyDataContext())
{
object[] parameters =  { param1, param2, param3 };

return context.Database.SqlQuery<myEntityType>("mySpName {0}, {1}, {2}",
parameters).ToList();
}

//หรือ

using(var context = new MyDataContext())
{  
return context.Database.SqlQuery<myEntityType>("mySpName {0}, {1}, {2}",
param1, param2, param3).ToList();
}

มันทำงานให้ฉันสำหรับ Assembly EntityFramework.dll, v4.4.0.0
Thulasiram

2
ถ้าคุณกำลังใช้ using (var context = new MyDataContext ()) ดังนั้น. ToList () เป็นสิ่งจำเป็น
Thulasiram

ฉันใช้เวลาพอสมควรในการค้นพบว่า. ToList () จำเป็นต้องได้รับชุดผลลัพธ์ที่ถูกต้อง
Halim

8

คำตอบส่วนใหญ่จะเปราะบางเพราะพวกเขาต้องอาศัยลำดับของพารามิเตอร์ ดีกว่าที่จะตั้งชื่อพารามิเตอร์ของ Stored Proc และให้ค่าพารามิเตอร์กับสิ่งเหล่านั้น

ในการใช้พารามิเตอร์ที่มีชื่อเมื่อโทร SP ของคุณโดยไม่ต้องกังวลเกี่ยวกับลำดับของพารามิเตอร์

การใช้ SQL Server ชื่อพารามิเตอร์ด้วย ExecuteStoreQuery และ ExecuteStoreCommand

อธิบายวิธีการที่ดีที่สุด ดีกว่าคำตอบของแดนมอร์คที่นี่

  • ไม่พึ่งพาสตริงที่ต่อกันและไม่พึ่งพาลำดับของพารามิเตอร์ที่กำหนดไว้ใน SP

เช่น:

var cmdText = "[DoStuff] @Name = @name_param, @Age = @age_param";
var sqlParams = new[]{
   new SqlParameter("name_param", "Josh"),
   new SqlParameter("age_param", 45)
};

context.Database.SqlQuery<myEntityType>(cmdText, sqlParams)

ดูเหมือนว่า "params" เป็นคำหลักที่สงวนไว้ดังนั้นฉันไม่คิดว่าคุณจะใช้มันได้ มิฉะนั้นนี่เป็นคำตอบที่เป็นประโยชน์สำหรับฉัน ขอบคุณ!
ooXei1sh

@ ooXei1sh - แก้ไขแล้วโดยใช้sqlParamsตัวแปร
Don Cheadle

คุณสามารถใส่คำนำหน้าด้วย @ เพื่อใช้คำสงวน แต่คุณไม่ควรทำ
StingyJack

6
db.Database.SqlQuery<myEntityType>("exec GetNewSeqOfFoodServing @p0,@p1,@p2 ", foods_WEIGHT.NDB_No, HLP.CuntryID, HLP.ClientID).Single()

หรือ

db.Database.SqlQuery<myEntityType>(
    "exec GetNewSeqOfFoodServing @param1, @param2", 
    new SqlParameter("param1", param1), 
    new SqlParameter("param2", param2)
);

หรือ

var cmdText = "exec [DoStuff] @Name = @name_param, @Age = @age_param";
var @params = new[]{
   new SqlParameter("name_param", "Josh"),
   new SqlParameter("age_param", 45)
};

db.Database.SqlQuery<myEntityType>(cmdText, @params)

หรือ

db.Database.SqlQuery<myEntityType>("mySpName {0}, {1}, {2}",
new object[] { param1, param2, param3 }).ToList();

3

ฉันใช้วิธีนี้:

var results = this.Database.SqlQuery<yourEntity>("EXEC [ent].[GetNextExportJob] {0}", ProcessorID);

ฉันชอบเพราะฉันเพียงแค่วางใน Guids และ Datetimes และ SqlQuery ทำการจัดรูปแบบทั้งหมดสำหรับฉัน


1

คำตอบของ @Tom Halladay นั้นถูกต้องด้วยการพูดถึงว่าคุณ shopuld ตรวจสอบค่า Null และส่ง DbNullable ถ้า params นั้นว่างเปล่าเพราะคุณจะได้รับการยกเว้นเช่น

ข้อความค้นหาที่กำหนดพารามิเตอร์ '... ' ต้องการพารามิเตอร์ '@parameterName' ซึ่งไม่ได้ระบุไว้

บางสิ่งเช่นนี้ช่วยฉันได้

public static object GetDBNullOrValue<T>(this T val)
{
    bool isDbNull = true;
    Type t = typeof(T);

    if (Nullable.GetUnderlyingType(t) != null)
        isDbNull = EqualityComparer<T>.Default.Equals(default(T), val);
    else if (t.IsValueType)
        isDbNull = false;
    else
        isDbNull = val == null;

    return isDbNull ? DBNull.Value : (object) val;
}

(เครดิตสำหรับวิธีนี้ไปที่https://stackoverflow.com/users/284240/tim-schmelter )

จากนั้นใช้มันเหมือน:

new SqlParameter("@parameterName", parameter.GetValueOrDbNull())

หรือวิธีแก้ปัญหาอื่นง่ายกว่า แต่ไม่ใช่ทั่วไป:

new SqlParameter("@parameterName", parameter??(object)DBNull.Value)

0

ฉันมีข้อความแสดงข้อผิดพลาดเดียวกันเมื่อฉันทำงานกับการเรียกโพรซีเดอร์ที่เก็บไว้ซึ่งใช้พารามิเตอร์อินพุตสองค่าและส่งคืนค่า 3 ค่าโดยใช้คำสั่ง SELECT และฉันแก้ไขปัญหาดังด้านล่างในแนวทางการใช้รหัสแรกของ EF

 SqlParameter @TableName = new SqlParameter()
        {
            ParameterName = "@TableName",
            DbType = DbType.String,
            Value = "Trans"
        };

SqlParameter @FieldName = new SqlParameter()
        {
            ParameterName = "@FieldName",
            DbType = DbType.String,
            Value = "HLTransNbr"
        };


object[] parameters = new object[] { @TableName, @FieldName };

List<Sample> x = this.Database.SqlQuery<Sample>("EXEC usp_NextNumberBOGetMulti @TableName, @FieldName", parameters).ToList();


public class Sample
{
    public string TableName { get; set; }
    public string FieldName { get; set; }
    public int NextNum { get; set; }
}

ปรับปรุง : ดูเหมือนกับ SQL SERVER 2005 คำหลัก EXEC ที่ขาดหายไปกำลังสร้างปัญหา ดังนั้นเพื่อให้มันทำงานกับ SQL Server ทุกเวอร์ชันฉันได้อัพเดตคำตอบและเพิ่มEXECในบรรทัดด้านล่าง

 List<Sample> x = this.Database.SqlQuery<Sample>(" EXEC usp_NextNumberBOGetMulti @TableName, @FieldName", param).ToList();

โปรดดูลิงค์ด้านล่าง ไม่จำเป็นต้องใช้ exec msdn.microsoft.com/en-us/data/jj592907.aspx
Ziggler

0

ฉันทำของฉันกับ EF 6.x เช่นนี้

using(var db = new ProFormDbContext())
            {
                var Action = 1; 
                var xNTID = "A239333";

                var userPlan = db.Database.SqlQuery<UserPlan>(
                "AD.usp_UserPlanInfo @Action, @NTID", //, @HPID",
                new SqlParameter("Action", Action),
                new SqlParameter("NTID", xNTID)).ToList();


            }

อย่าเพิ่ม sqlparameter เป็นสองเท่าในบางคนที่ทำสิ่งนี้กับตัวแปรของพวกเขา

var Action = new SqlParameter("@Action", 1);  // Don't do this, as it is set below already.
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.