【问题标题】:How to use DbContext.Database.SqlQuery<TElement>(sql, params) with stored procedure? EF Code First CTP5如何将 DbContext.Database.SqlQuery<TElement>(sql, params) 与存储过程一起使用? EF 代码优先 CTP5
【发布时间】:2011-02-02 11:01:51
【问题描述】:

我有一个包含三个参数的存储过程,我一直在尝试使用以下方法返回结果:

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

起初我尝试使用 SqlParameter 对象作为参数,但这不起作用并抛出了 SqlException 并显示以下消息:

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

所以我的问题是如何将此方法与需要参数的存储过程一起使用?

谢谢。

【问题讨论】:

  • 您使用的是什么版本的 SQL Server?我在兼容(90)模式下在 2008 年运行的代码遇到问题,但是当我针对 2005 年运行它时,它会因语法错误而失败。
  • @Gats - 我在使用 SQL 2005 时遇到了同样的问题。在存储过程名称之前添加“EXEC”。我在此处发布了此信息以供将来参考:stackoverflow.com/questions/6403930/…

标签: c# sql ado.net linq-to-entities entity-framework-ctp5


【解决方案1】:

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

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

【讨论】:

  • 如何使这个方法适用于可空类型?我用可空小数尝试了这个,但是当小数为空时,我得到错误说参数丢失。但是,@DanMork 提到的以下方法可以找到。
  • 传递DbNull.Value而不是空值能解决问题吗?
  • 您也可以使用 \@p# 语法来避免在 context.Database.SqlQuerymsdn.microsoft.com/en-US/data/jj592907。 (注意:必须使用 \@ 来避免用户通知,阅读时应不带反斜杠。)
  • 如果你使用的是DateTime参数,你也需要指定参数类型,而不仅仅是名称和值。例如:dbContext.Database.SqlQuery("spGetInvoices @dateFrom, @dateTo", new SqlParameter { ParameterName = "dateFrom", SqlDbType = SqlDbType.DateTime, Value = startDate }, new SqlParameter { ParameterName = "dateTo", SqlDbType = SqlDbType.DateTime,值 = endDate });另一个重要的事情是尊重参数的顺序。
  • 你能检查一下我做错了什么吗?我已经按照你的指导方针,但完全没有效果stackoverflow.com/questions/27926598/…
【解决方案2】:

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

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

【讨论】:

  • 不得不对此进行投票。虽然它没有被接受为答案,但它比选择作为答案的解决方案更容易编写解决方案。
  • 这个语法让我有点担心。它是否容易受到 SQL 注入的影响?我会假设 EF 正在运行“EXEC mySpName @Param1 =”,并且有可能发送“x' GO [恶意脚本]”并导致一些问题?
  • @TomHalladay 没有 SQL 注入的风险 - 该方法仍将根据参数类型引用和转义参数,与 @ 样式参数相同。因此,对于字符串参数,您可以在语句中使用不带引号的“SELECT * FROM Users WHERE email={0}”。
  • 在我的例子中,我们有很多 SP 的可选参数并且不能使用 SqlParameters 调用,但是这种格式可以解决问题,只需要在开头添加“EXEC”。谢谢。
  • 如果您必须使用可选参数为 proc 指定参数,则此答案很有用。无效的示例:ProcName @optionalParam1 = @opVal1, @optionalParam2 = @opVal2 有效的示例:ProcName @optionalParam1 = {0}, @optionalParam2 = {1}
【解决方案3】:

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

你们是救生员,但正如@Dan Mork 所说,您需要将 EXEC 添加到组合中。让我绊倒的是:

  • Proc 名称前的“EXEC”
  • 参数之间的逗号
  • 在参数上切掉“@” 定义(但不确定是否需要该位)。

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

【讨论】:

  • +1。投票率较高的答案都不包括exec,但我可以确认,如果我省略它,我会得到一个例外。
  • 谢谢,我遇到了一个错误,添加了 EXEC 并且错误消失了。奇怪的部分是如果我做了 context.Database.SqlQuery("ProcName '" + param1 + "','" + param2 + "'");它起作用了,但是如果我添加了参数,它直到我添加了 EXEC 关键字才起作用。
  • 仅供参考:我不需要 exec 关键字。 +1 用于删除参数上的 @,这总是让我感到困惑。
  • +1,我错过了 EXEC 并不断收到带有消息的 SqlExceptions:'procName' 附近的语法不正确。
  • @Ziggler 你是 2005 年还是更新的?对于我们这些反对 2005 年的人来说,EXEC 关键字主要是一个问题。
【解决方案4】:
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
  • 如果你使用 using(var context = new MyDataContext()) 那么 .ToList() 是强制性的。
  • 我花了很多时间才发现 .ToList() 是获得正确结果集所必需的。
【解决方案5】:

大多数答案都很脆弱,因为它们依赖于 SP 参数的顺序。最好命名 Stored Proc 的参数并为其赋予参数化值。

为了在调用你的SP时使用命名参数,而不用担心参数的顺序

Using SQL Server named parameters with ExecuteStoreQuery and ExecuteStoreCommand

描述最佳方法。比 Dan Mork 的回答要好。

  • 不依赖连接字符串,也不依赖 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 - 已修复,使用 sqlParams 变量
  • 可以在它前面加上@来使用保留字,但你真的不应该
  • 谢谢,所有其他答案都要求参数的顺序相同。
【解决方案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();

【讨论】:

    【解决方案7】:

    我用这个方法:

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

    我喜欢它,因为我只是添加了 Guid 和 Datetimes,而 SqlQuery 会为我执行所有格式设置。

    【讨论】:

      【解决方案8】:

      @Tom Halladay 的回答是正确的,提到您还可以检查 null 值并在参数为 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)
      

      【讨论】:

        【解决方案9】:

        当我使用 SELECT 语句调用带有两个输入参数并返回 3 个值的存储过程时,我遇到了相同的错误消息,我在 EF Code First Approach 中解决了如下问题

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

        【讨论】:

        【解决方案10】:

        我是这样使用 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.
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多