Bagaimana cara menggunakan DbContext.Database.SqlQuery <TElement> (sql, params) dengan prosedur tersimpan? Kode EF Pertama CTP5

250

Saya memiliki prosedur tersimpan yang memiliki tiga parameter dan saya telah mencoba menggunakan yang berikut untuk mengembalikan hasilnya:

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

Pada awalnya saya mencoba menggunakan SqlParameterobjek sebagai params tetapi ini tidak berhasil dan melemparkan SqlExceptionpesan berikut:

Prosedur atau fungsi 'mySpName' mengharapkan parameter '@ param1', yang tidak disertakan.

Jadi pertanyaan saya adalah bagaimana Anda dapat menggunakan metode ini dengan prosedur tersimpan yang mengharapkan parameter?

Terima kasih.

jempol listrik
sumber
Versi SQL Server apa yang Anda gunakan? Saya mengalami masalah dengan kode yang berfungsi pada 2008 dalam mode compat (90), tetapi ketika saya menjalankannya terhadap 2005 gagal dengan kesalahan sintaks.
Gats
4
@ Gats - Saya mengalami masalah yang sama w / SQL 2005. Tambahkan "EXEC" sebelum nama prosedur tersimpan. Saya memposting info ini di sini untuk referensi di masa mendatang: stackoverflow.com/questions/6403930/…
Dan Mork

Jawaban:

389

Anda harus menyediakan instance SqlParameter dengan cara berikut:

context.Database.SqlQuery<myEntityType>(
    "mySpName @param1, @param2, @param3",
    new SqlParameter("param1", param1),
    new SqlParameter("param2", param2),
    new SqlParameter("param3", param3)
);
Devart
sumber
3
Bagaimana Anda membuat metode ini bekerja dengan tipe nullable? Saya mencoba ini dengan desimal nullable, tetapi ketika desimal adalah nol saya mendapatkan kesalahan yang mengatakan parameter tidak ada. Namun, metode di bawah ini yang disebutkan oleh @DanMork works find.
Paul Johnson
2
Apakah lewat DbNull.Valuealih-alih nol menyelesaikan masalah?
Alireza
29
Anda juga dapat menggunakan sintaks \ @ p # untuk menghindari penggunaan SqlParameter seperti pada context.Database.SqlQuery <myEntityType ("mySpName \ @ p0, \ @ p1, \ @ p2", param1, param2, param3). Sumber: msdn.microsoft.com/en-US/data/jj592907 . (Catatan: harus menggunakan \ @ untuk menghindari pemberitahuan pengguna, harus dibaca tanpa backslash.)
Marco
3
Jika Anda menggunakan parameter DateTime, Anda perlu menentukan tipe parameter juga, tidak hanya nama dan nilai. Sebagai contoh: dbContext.Database.SqlQuery <Invoice> ("spGetInvoices @dateFrom, @dateTo", SqlParameter baru {ParameterName = "dateFrom", SqlDbType = SqlDbType.DateTime, Value = startDate}, parameter tanggal "ParameterTabel = parameter" ParameterTabel parameter) " SqlDbType = SqlDbType.DateTime, Value = endDate}); Hal penting lainnya adalah untuk menghormati urutan parameter.
Francisco Goldenstein
dapatkah Anda memeriksa apa yang saya lakukan salah saya telah mengikuti pedoman Anda tetapi tidak ada efek sama sekali stackoverflow.com/questions/27926598/…
Toxic
129

Anda juga dapat menggunakan parameter "sql" sebagai penentu format:

context.Database.SqlQuery<MyEntityType>("mySpName @param1 = {0}", param1)
Dan Mork
sumber
Harus memilih ini. Meskipun tidak diterima sebagai jawabannya, itu jauh lebih mudah untuk menulis solusi daripada yang dipilih sebagai jawaban.
Nikkoli
10
Sintaks ini sedikit mengkhawatirkan saya. Apakah rentan terhadap injeksi SQL? Saya menganggap EF menjalankan "EXEC mySpName @ Param1 =", dan apakah mungkin mengirim "x 'GO [skrip berbahaya]" dan menyebabkan beberapa masalah?
Tom Halladay
10
@ TomHalladay tidak ada risiko injeksi SQL - metode ini masih akan mengutip dan melepaskan parameter berdasarkan jenisnya, sama dengan params @ style. Jadi untuk parameter string Anda akan menggunakan "SELECT * FROM Users WHERE email = {0}" tanpa tanda kutip dalam pernyataan Anda.
Ross McNab
dalam kasus saya, kami memiliki banyak parameter opsional untuk SP dan tidak bekerja panggilan dengan SqlParameters tetapi format ini melakukan trik, hanya harus menambahkan 'EXEC' di awal. Terima kasih.
Onur Topal
1
Jawaban ini berguna jika Anda harus menentukan parameter ke proc dengan parameter opsional. Contoh yang tidak berfungsi: ProcName @optionalParam1 = @opVal1, @optionalParam2 = @opVal2 Contoh yang bekerja:ProcName @optionalParam1 = {0}, @optionalParam2 = {1}
Garrison Neely
72

Solusi ini (hanya) untuk SQL Server 2005

Kalian adalah penyelamat, tetapi seperti yang dikatakan @Dan Mork, Anda harus menambahkan EXEC ke dalam campuran. Apa yang membuat saya tersandung adalah:

  • 'EXEC' sebelum Nama Proc
  • Koma di antara Params
  • Memotong '@' pada Definisi Param (tidak yakin bahwa bit diperlukan meskipun).

:

context.Database.SqlQuery<EntityType>(
    "EXEC ProcName @param1, @param2", 
    new SqlParameter("param1", param1), 
    new SqlParameter("param2", param2)
);
Tom Halladay
sumber
21
+1. Tidak satu pun dari jawaban yang lebih tinggi termasuk exec, tetapi saya dapat mengkonfirmasi bahwa saya mendapatkan pengecualian jika saya menghilangkannya.
Jordan Grey
Terima kasih, saya mendapatkan kesalahan, menambahkan EXEC dan kesalahan hilang. Bagian yang aneh adalah jika saya melakukan context.Database.SqlQuery <EntityType> ("ProcName '" + param1 + "', '" + param2 + "'"); itu berfungsi, tetapi jika saya menambahkan parameter itu tidak berfungsi sampai saya menambahkan kata kunci EXEC.
Solmead
2
FYI: Saya tidak memerlukan execkata kunci. +1 untuk penghapusan @ pada params, yang selalu mengacaukan saya.
Nathan Koop
+1, saya kehilangan EXEC dan terus mendapatkan SqlExceptions dengan pesan: Sintaksis salah dekat 'procName'.
A. Murray
1
@ Ziggler apakah Anda di tahun 2005 atau lebih baru? Kata kunci EXEC terutama menjadi masalah bagi kita yang menentang 2005.
Tom Halladay
15
return context.Database.SqlQuery<myEntityType>("mySpName {0}, {1}, {2}",
new object[] { param1, param2, param3 });

//Atau

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

//Atau

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

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

//Atau

using(var context = new MyDataContext())
{  
return context.Database.SqlQuery<myEntityType>("mySpName {0}, {1}, {2}",
param1, param2, param3).ToList();
}
Thulasiram
sumber
ini bekerja untuk saya untuk Assembly EntityFramework.dll, v4.4.0.0
Thulasiram
2
jika Anda menggunakan using (var context = new MyDataContext ()) maka .ToList () wajib diisi.
Thulasiram
Saya menghabiskan beberapa waktu untuk mengetahui bahwa .ToList () wajib untuk mendapatkan hasil yang benar.
Halim
8

Sebagian besar jawaban rapuh karena mereka bergantung pada urutan parameter SP. Lebih baik memberi nama par Stored Proc dan memberikan nilai parameter untuk itu.

Untuk menggunakan param Bernama saat memanggil SP Anda, tanpa khawatir tentang urutan parameter

Menggunakan parameter bernama SQL Server dengan ExecuteStoreQuery dan ExecuteStoreCommand

Menjelaskan pendekatan terbaik. Lebih baik daripada jawaban Dan Mork di sini.

  • Tidak bergantung pada string yang digabungkan, dan tidak bergantung pada urutan parameter yang didefinisikan dalam SP.

Misalnya:

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)
Don Cheadle
sumber
Tampaknya "params" adalah kata kunci yang dipesan, jadi saya tidak berpikir Anda dapat menggunakannya seperti itu. Kalau tidak, ini adalah jawaban yang bermanfaat bagi saya. Terima kasih!
ooXei1sh
@ ooXei1sh - diperbaiki, menggunakan sqlParamsvariabel
Don Cheadle
Anda dapat awalan dengan @ untuk menggunakan kata yang dipesan, tetapi Anda benar -
StingyJack
6
db.Database.SqlQuery<myEntityType>("exec GetNewSeqOfFoodServing @p0,@p1,@p2 ", foods_WEIGHT.NDB_No, HLP.CuntryID, HLP.ClientID).Single()

atau

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

atau

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)

atau

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

Saya menggunakan metode ini:

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

Saya suka karena saya baru saja memasukkan Guids dan Datetimes dan SqlQuery melakukan semua format untuk saya.

Malcolm O'Hare
sumber
1

@ Tom Halladay jawaban benar dengan menyebutkan bahwa Anda shopuld juga memeriksa nilai-nilai nol dan mengirim DbNullable jika params nol karena Anda akan mendapatkan pengecualian seperti

Kueri parameterisasi '...' mengharapkan parameter '@parameterName', yang tidak disertakan.

Sesuatu seperti ini membantu saya

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

(kredit untuk metode ini masuk ke https://stackoverflow.com/users/284240/tim-schmelter )

Kemudian gunakan seperti:

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

atau solusi lain, lebih sederhana, tetapi tidak generik adalah:

new SqlParameter("@parameterName", parameter??(object)DBNull.Value)
emanuel.virca
sumber
0

Saya memiliki pesan kesalahan yang sama ketika saya bekerja dengan memanggil prosedur tersimpan yang mengambil dua parameter input dan mengembalikan 3 nilai menggunakan pernyataan SELECT dan saya memecahkan masalah seperti di bawah ini di Pendekatan Pertama Kode 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; }
}

UPDATE : Sepertinya SQL SERVER 2005 hilang kata kunci EXEC menciptakan masalah. Jadi untuk membuatnya bekerja dengan semua versi SQL SERVER, saya memperbarui jawaban saya dan menambahkan EXEC di bawah baris

 List<Sample> x = this.Database.SqlQuery<Sample>(" EXEC usp_NextNumberBOGetMulti @TableName, @FieldName", param).ToList();
Ziggler
sumber
Silakan lihat tautan di bawah ini. Tidak perlu menggunakan exec msdn.microsoft.com/en-us/data/jj592907.aspx
Ziggler
0

Saya melakukan tugas saya dengan EF 6.x seperti ini:

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


            }

Jangan gandakan pada sqlparameter beberapa orang terbakar melakukan ini ke variabel mereka

var Action = new SqlParameter("@Action", 1);  // Don't do this, as it is set below already.
Tom Stickel
sumber