【问题标题】:EF ExecuteStoredCommand with ReturnValue parameter带有 ReturnValue 参数的 EF ExecuteStoredCommand
【发布时间】:2012-01-17 03:44:02
【问题描述】:

我正在创建一个需要与旧代码交互的新应用程序:(。

我试图调用的存储过程使用 RETURN 作为其结果。我尝试执行和使用返回值导致异常:

InvalidOperationException:执行命令时,参数必须是数据库参数或值。

不希望更改存储过程以另一种方式返回值,因为它要么需要更新旧版应用程序,要么需要维护几乎重复的存储过程。

遗留的存储过程概要:

DECLARE @MyID INT
INSERT INTO MyTable ...
SELECT @MyID = IDENTITY()
RETURN @MyID

我的实体框架/DbContext 工作,产生上述 InvalidOperationException。

 SqlParameter parm = new SqlParameter() {
    ParameterName = "@MyID",
    Direction = System.Data.ParameterDirection.ReturnValue
 };

 DbContext.Database.ExecuteSqlCommand("EXEC dbo.MyProc", parm);

寻找任何和所有不需要修改存储过程的解决方案。

【问题讨论】:

    标签: sql-server entity-framework-4.1 ef-code-first


    【解决方案1】:

    您可以改为将存储过程的返回值捕获到输出参数中:

    SqlParameter parm = new SqlParameter() {  
        ParameterName = "@MyID",  
        SqlDbType = SqlDbType.Int,
        Direction = System.Data.ParameterDirection.Output  
     };  
    
    Database.ExecuteSqlCommand("exec @MyId = dbo.MyProc", parm);
    
    int id = (int)parm.Value;
    

    【讨论】:

    • 只有不尝试用SqlQuery 欺骗你的答案,而不是ExecuteSqlCommand 的解决方案。这就是让我绊倒的原因,你会认为 @MyId 应该是 ParameterDirection.ReturnValue 但出于某种无法理解的原因,它必须是 ParameterDirection.Output
    【解决方案2】:

    我知道有点晚了,但这对我有用:

    var param = new SqlParameter("@Parameter1", txtBoxORsmth.text);
    
    someVariable = ctx.Database.SqlQuery<int>("EXEC dbo.MyProc", param).First();
    

    【讨论】:

      【解决方案3】:

      您没有使用ExecuteSqlCommand

      您可以从 DbContext.Database.Connection 获取底层连接并使用原始 ADO.NET(CreateCommand()ExecuteNonQuery()、...)

      【讨论】:

        【解决方案4】:

        错误信息

        InvalidOperationException:执行命令时,参数必须是数据库参数或值。

        意味着您没有在 SQLParameters 的参数列表中提供正确的类型(或代码 sn-p 中未显示的其他内容)。

        在我的例子中,我忘记删除 MergeOption,因为我更改了 SQL 命令的执行方式。

        【讨论】:

          【解决方案5】:

          这个extension method 现在将为您完成所有肮脏的工作。请参阅 SO here 上的完整描述。

          【讨论】:

            【解决方案6】:

            为With参数示例创建表,用于测试或根据您的更改第二个sql查询。

            CREATE TABLE [dbo].[Test](
                [Id] [int] IDENTITY(1,1) NOT NULL,
                [Name] [varchar](50) NOT NULL,
             CONSTRAINT [PK_Test] PRIMARY KEY CLUSTERED 
            (
                [Id] ASC
            )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, 
            ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
            ) ON [PRIMARY]
            

            //============================================== ==============//

                    public void Test()
                    {
                              using (var db = new DbContext())
                              {
                                  string sql = "dbo.MyProc";  //With Out Parameter
            
                              int id1 = (int)db.Database.SqlQuery<decimal>(sql).FirstOrDefault();
                              db.SaveChanges();
            
                              //Or
            
                              sql = "INSERT Test(Name) values({0}) SELECT SCOPE_IDENTITY();";  //With Parameter
                              int id2 = (int)db.Database.SqlQuery<decimal>(sql, new object[] { "Thulasi Ram.S" }).FirstOrDefault();
                              db.SaveChanges();
                          }
                    }
            

            【讨论】:

              【解决方案7】:

              我尝试了上述方法,但只有这种方法对我有用(必须具有'ToList()'功能):

               SqlParameter res = new SqlParameter()
                      {
                          ParameterName = "Count",
                          Value=1,
                          Direction = System.Data.ParameterDirection.Output
                      };
              db.Database.SqlQuery<object>(
                       "[dbo].[GetWorkerCountBySearchConditions] @Count ,
                       res
                       ).ToList();
                      return Convert.ToInt32(res.Value);
              

              【讨论】:

                【解决方案8】:

                这将使用 DBContext 从存储过程中返回 int:

                var newId = DbContext.Database.SqlQuery<int>("EXEC dbo.MyProc @MyID = {0}", parm).First();
                

                【讨论】:

                • 这是一个糟糕的建议。此代码易受 SQL 注入攻击。 很少这种语句构造和执行是个好主意。始终尝试使用参数化查询。
                • @NathanAldenSr - SqlQuery 方法自动将您提供的参数转换为 DbParameters。这是一个参数化查询——它必须是为了调用一个带参数的存储过程。 msdn.microsoft.com/en-us/library/…
                • @Colin 啊,我的错,当时没有更好地理解方法。
                【解决方案9】:

                我确信这不是唯一有效的答案,而是我最终使用并成功运行的答案。

                关键似乎是命名 ReturnValue 参数 RetVal

                SqlParameter id = create.Parameters.Add("RetVal", System.Data.SqlDbType.Int);
                id.Direction = System.Data.ParameterDirection.ReturnValue;
                

                把它们放在一起:

                SqlCommand proc = new SqlCommand("dbo.MyProc", new SqlConnection(<connection string>));
                proc.CommandType = System.Data.CommandType.StoredProcedure;
                
                SqlParameter id = create.Parameters.Add("RetVal", System.Data.SqlDbType.Int);
                id.Direction = System.Data.ParameterDirection.ReturnValue;
                
                proc.ExecuteNonQuery();
                
                int newId = Convert.ToInt32(id.Value);
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2022-01-26
                  • 1970-01-01
                  • 1970-01-01
                  • 2020-11-23
                  • 1970-01-01
                  • 2017-10-23
                  • 2019-06-21
                  • 2020-11-27
                  相关资源
                  最近更新 更多