如何在存储过程中使用DbContext.Database.SqlQuery <TElement>(sql,params)?EF代码优先CTP5


250

我有一个具有三个参数的存储过程,并且我一直在尝试使用以下命令返回结果:

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

最初,我尝试使用SqlParameter对象作为参数,但这没有用,并向其SqlException显示以下消息:

过程或函数“ mySpName”需要未提供的参数“ @ param1”。

所以我的问题是,如何在需要参数的存储过程中使用此方法?

谢谢。


您正在使用哪个版本的SQL Server?我无法在兼容(90)模式下的2008上运行的代码遇到麻烦,但是当我针对2005运行它时,它将失败并出现语法错误。
服务贸易总协定

4
@Gats-我在使用SQL 2005时遇到了相同的问题。在存储过程名称之前添加“ EXEC”。我在这里发布此信息以供将来参考:stackoverflow.com/questions/6403930/...
丹莫克

Answers:


389

您应该通过以下方式提供SqlParameter实例:

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

3
您将如何使此方法与可为null的类型一起使用?我尝试使用可为空的小数,但是当小数为空时,出现错误,提示缺少参数。但是,@ DanMork工程下面提到的方法可以找到。
保罗·约翰逊

2
通过传递DbNull.Value而不是null 是否可以解决问题?
Alireza

29
您还可以使用\ @ p#语法避免在context.Database.SqlQuery <myEntityType(“ mySpName \ @ p0,\ @ p1,\ @ p2”,param1,param2,param3)中使用SqlParameter。来源:msdn.microsoft.com/zh-CN/data/jj592907。(注意:必须使用\ @以避免用户通知,应在读取时不带反斜杠。)
Marco Marco

3
如果使用DateTime参数,则还需要指定参数类型,而不仅是名称和值。例如:dbContext.Database.SqlQuery <Invoice>(“ spGetInvoices @dateFrom,@dateTo”,新的SqlParameter {ParameterName =“ dateFrom”,SqlDbType = SqlDbType.DateTime,Value = startDate},新的SqlParameter {ParameterName =“ dateTo”, SqlDbType = SqlDbType.DateTime,Value = endDate});另一个重要的事情是遵守参数的顺序。
Francisco Goldenstein 2014年

能不能请检查什么,我做错了我也跟着你理念为指导,但都没有效果stackoverflow.com/questions/27926598/...

129

另外,您可以使用“ sql”参数作为格式说明符:

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

不得不对此进行投票。虽然它不被接受为答案,但是它比选择作为答案的解决方案更容易编写解决方案。
Nikkoli,2012年

10
这个语法让我有些担心。它会受到SQL注入的影响吗?我假设EF正在运行“ EXEC mySpName @ Param1 =”,并且可能会发送“ x'GO [恶意脚本]”并引起某些问题?
汤姆·哈拉迪

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 2014年

72

此解决方案(仅)用于SQL Server 2005

你们是救星,但正如@Dan Mork所说,您需要在其中添加EXEC。使我震惊的是:

  • 过程名称前的“ EXEC”
  • 参数之间的逗号
  • 在参数定义中切掉“ @”(尽管不确定该位是否必需)。

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

21
+1。投票率较高的答案均未包含exec,但我可以确认如果忽略此异常。
乔丹·格雷

谢谢,我遇到一个错误,添加了EXEC,错误消失了。奇怪的是,如果我做了context.Database.SqlQuery <EntityType>(“ ProcName'” + param1 +“','” + param2 +“'”)); 它起作用了,但是如果我添加了参数,那么直到添加EXEC关键字后它才起作用。
Solmead 2014年

2
仅供参考:我不需要exec关键字。+1删除参数上的@,这总是让我感到困惑。
内森·库普

+1,我错过了EXEC并不断收到消息SqlExceptions:'procName'附近的语法不正确。
A. Murray

1
@Ziggler您在2005年或更高版本上吗?EXEC关键字对于我们这些人来说是2005
。– Tom Halladay 2015年

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()。
图拉西兰

我花了很多时间来发现.ToList()是获得正确结果集所必需的。
哈里姆

8

大多数答案都很脆弱,因为它们依赖于SP参数的顺序。最好命名存储的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)

似乎“参数”是保留的关键字,所以我认为您不能像这样使用它。否则,这对我来说是一个有用的答案。谢谢!
ooXei1sh

@ ooXei1sh-固定,使用sqlParams变量
Don Cheadle

可以在@
前面加上

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的答案是正确的,提到您还应该检查null值,如果params为null,则发送DbNullable,因为您会得到类似的异常

参数化查询“ ...”需要未提供的参数“ @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

当我使用一个使用两个输入参数并使用SELECT语句返回3个值的存储过程时,我遇到了相同的错误消息,并且在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/zh-cn/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.
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.