Làm cách nào để sử dụng DbContext.Database.SqlQuery <TEuity> (sql, params) với thủ tục được lưu trữ? Mã EF CTP5 đầu tiên


250

Tôi có một quy trình được lưu trữ có ba tham số và tôi đã cố gắng sử dụng các tham số sau để trả về kết quả:

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

Lúc đầu, tôi đã thử sử dụng SqlParametercác đối tượng làm thông số nhưng điều này không hiệu quả và đã gửi một SqlExceptionthông báo sau:

Quy trình hoặc chức năng 'mySpName' mong đợi tham số '@ param1', không được cung cấp.

Vì vậy, câu hỏi của tôi là làm thế nào bạn có thể sử dụng phương pháp này với một thủ tục được lưu trữ mà mong đợi các tham số?

Cảm ơn.


Phiên bản SQL Server nào bạn đang sử dụng? Tôi gặp sự cố với mã hoạt động vào năm 2008 ở chế độ compat (90), nhưng khi tôi chạy nó vào năm 2005 thì nó bị lỗi cú pháp.
Gats

4
@Gats - Tôi gặp vấn đề tương tự w / SQL 2005. Thêm "EXEC" trước tên thủ tục được lưu trữ. Tôi đã đăng thông tin này lên đây để tham khảo trong tương lai: stackoverflow.com/questions/6403930/ cấp
Dan Mork

Câu trả lời:


389

Bạn nên cung cấp các phiên bản SqlParameter theo cách sau:

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

3
Làm thế nào bạn có thể làm cho phương pháp này hoạt động với các loại nullable? Tôi đã thử điều này với số thập phân nullable, nhưng khi số thập phân là null tôi gặp lỗi khi nói tham số bị thiếu. Tuy nhiên, phương pháp dưới đây được đề cập bởi @DanMork hoạt động tìm thấy.
Paul Johnson

2
Liệu vượt qua DbNull.Valuethay vì null giải quyết vấn đề?
Alireza

29
Bạn cũng có thể sử dụng cú pháp \ @ p # để tránh sử dụng SqlParameter như trong bối cảnh.Database.SqlQuery <myEntityType ("mySpName \ @ p0, \ @ p1, \ @ p2", param1, param2, param3). Nguồn: msdn.microsoft.com/en-US/data/jj592907 . (Lưu ý: phải sử dụng \ @ để tránh thông báo của người dùng, nên được đọc mà không có dấu gạch chéo ngược.)
Marco

3
Nếu bạn đang sử dụng tham số DateTime, bạn cũng cần chỉ định loại tham số, không chỉ tên và giá trị. Ví dụ: dbContext.Database.SqlQuery <Invoice> ("spGetInvoices @dateFrom, @dateTo", new SqlParameter {ParameterName = "dateFrom", SqlDbType = SqlDbType.DateTime, Value = startDate SqlDbType = SqlDbType.DateTime, Value = endDate}); Một điều quan trọng khác là tôn trọng thứ tự của các tham số.
Francisco Goldenstein

bạn có thể vui lòng kiểm tra những gì tôi đang làm sai không? Tôi đã làm theo hướng dẫn của bạn nhưng không có tác dụng gì với stackoverflow.com/questions/27926598/ chủ đề
Độc hại

129

Ngoài ra, bạn có thể sử dụng tham số "sql" làm công cụ xác định định dạng:

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

Phải bỏ phiếu này. Mặc dù nó không được chấp nhận là câu trả lời, nhưng đây là một giải pháp dễ viết hơn nhiều so với giải pháp được chọn làm câu trả lời.
Nikkoli

10
Cú pháp này liên quan đến tôi một chút. Nó có dễ bị tiêm SQL không? Tôi cho rằng EF đang chạy "EXEC mySpName @ Param1 =" và có thể gửi "x 'GO [tập lệnh độc hại]" và gây ra một số vấn đề?
Tom Halladay

10
@TomHalladay không có rủi ro về việc tiêm SQL - phương thức vẫn sẽ trích dẫn và thoát các tham số dựa trên loại của chúng, giống như các tham số kiểu @. Vì vậy, đối với tham số chuỗi, bạn sẽ sử dụng "CHỌN * TỪ người dùng WHERE email = {0}" mà không có dấu ngoặc kép trong câu lệnh của bạn.
Ross McNab

trong trường hợp của tôi, chúng tôi có rất nhiều tham số tùy chọn cho SP và không thực hiện các cuộc gọi với SqlParameter nhưng định dạng này thực hiện thủ thuật, chỉ cần thêm 'EXEC' vào đầu. Cảm ơn.
Onur Topal

1
Câu trả lời này rất hữu ích nếu bạn phải chỉ định tham số cho một Proc với các tham số tùy chọn. Ví dụ không hoạt động: ProcName @optionalParam1 = @opVal1, @optionalParam2 = @opVal2 Ví dụ không hoạt động:ProcName @optionalParam1 = {0}, @optionalParam2 = {1}
Garrison Neely

72

Giải pháp này là (chỉ) cho SQL Server 2005

Các bạn là phao cứu sinh, nhưng như @Dan Mork đã nói, bạn cần thêm EXEC vào hỗn hợp. Điều khiến tôi vấp ngã là:

  • 'EXEC' trước tên Proc
  • Dấu phẩy ở giữa Params
  • Cắt bỏ '@' trên Định nghĩa Tham số (mặc dù không chắc chắn rằng bit là bắt buộc).

:

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

21
+1. Không có câu trả lời nào được bình chọn cao hơn bao gồm exec, nhưng tôi có thể xác nhận rằng tôi nhận được một ngoại lệ nếu tôi bỏ qua nó.
Jordan Gray

Cảm ơn bạn, tôi đã nhận được một lỗi, thêm EXEC và lỗi đã biến mất. Phần kỳ lạ là nếu tôi đã làm bối cảnh.Database.SqlQuery <EntityType> ("ProcName '" + param1 + "', '" + param2 + "'"); nó đã hoạt động, nhưng nếu tôi thêm các tham số thì nó không hoạt động cho đến khi tôi thêm từ khóa EXEC.
Solmead

2
FYI: Tôi không yêu cầu exectừ khóa. +1 cho việc xóa @ trên các thông số, điều đó luôn làm tôi bối rối.
Nathan Koop

+1, tôi đã thiếu EXEC và liên tục nhận được SqlExceptions với thông báo: Cú pháp không chính xác gần 'ProcName'.
A. Murray

1
@Ziggler bạn vào năm 2005 hay mới hơn? Từ khóa EXEC chủ yếu là một vấn đề đối với những người trong chúng ta đi ngược lại năm 2005.
Tom Halladay

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

//Hoặc là

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

//Hoặc là

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

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

//Hoặc là

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

nó đang làm việc cho tôi cho hội EntityFramework.dll, v4.4.0.0
Thicesiram

2
nếu bạn đang sử dụng (var context = new MyDataContext ()) thì .ToList () là bắt buộc.
Thicesiram

Tôi đã dành một khoảng thời gian tốt để khám phá ra rằng .ToList () là bắt buộc để có được tập kết quả chính xác.
Halim

8

Hầu hết các câu trả lời đều dễ vỡ vì chúng dựa vào thứ tự các tham số của SP. Tốt hơn là đặt tên cho các tham số của Proc được lưu trữ và đưa ra các giá trị được tham số hóa cho các tham số đó.

Để sử dụng thông số được đặt tên khi gọi SP của bạn, không phải lo lắng về thứ tự của các tham số

Sử dụng SQL Server có tên tham số với ExecuteStoreQuery và ExecuteStoreCommand

Mô tả cách tiếp cận tốt nhất. Tốt hơn câu trả lời của Dan Mork ở đây.

  • Không dựa vào các chuỗi nối và không dựa vào thứ tự của các tham số được xác định trong SP.

Ví dụ:

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)

Có vẻ như "params" là một từ khóa dành riêng, vì vậy tôi không nghĩ bạn có thể sử dụng nó như thế. Nếu không thì đây là một câu trả lời hữu ích cho tôi. Cảm ơn!
ooXei1sh

@ ooXei1sh - đã sửa, sử dụng sqlParamsbiến
Don Cheadle

bạn có thể thêm tiền tố vào @ để sử dụng một từ dành riêng, nhưng bạn thực sự không nên
StingyJack

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

hoặc là

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

hoặc là

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)

hoặc là

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

3

Tôi sử dụng phương pháp này:

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

Tôi thích nó bởi vì tôi chỉ cần thả vào Guids và Datetimes và SqlQuery thực hiện tất cả các định dạng cho tôi.


1

Câu trả lời của @Tom Halladay là chính xác với đề cập rằng bạn shopuld cũng kiểm tra các giá trị null và gửi DbNullable nếu params là null vì bạn sẽ có một ngoại lệ như

Truy vấn được tham số hóa '...' mong đợi tham số '@parameterName', không được cung cấp.

Một cái gì đó như thế này đã giúp tôi

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;
}

(tín dụng cho phương thức này được truy cập https://stackoverflow.com/users/284240/tim-schmelter )

Sau đó sử dụng nó như:

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

hoặc một giải pháp khác, đơn giản hơn, nhưng không chung chung sẽ là:

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

0

Tôi đã có cùng một thông báo lỗi khi tôi đang làm việc với việc gọi một thủ tục được lưu trữ có hai tham số đầu vào và trả về 3 giá trị bằng cách sử dụng câu lệnh SELECT và tôi đã giải quyết vấn đề như dưới đây trong Cách tiếp cận đầu tiên của Mã 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; }
}

CẬP NHẬT : Có vẻ như với SQL SERVER 2005 thiếu từ khóa EXEC đang tạo ra vấn đề. Vì vậy, để cho phép nó hoạt động với tất cả các phiên bản SQL SERVER, tôi đã cập nhật câu trả lời của mình và thêm EXEC vào dòng dưới đây

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

Xin vui lòng xem liên kết dưới đây. Không cần sử dụng exec msdn.microsoft.com/en-us/data/jj592907.aspx
Ziggler

0

Tôi đã làm việc với EF 6.x như thế này:

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();


            }

Đừng nhân đôi thông số sqlparameter, một số người bị đốt cháy khi làm điều này với biến của họ

var Action = new SqlParameter("@Action", 1);  // Don't do this, as it is set below already.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.