使用 `db.Database.SqlQuery<model>` 后如何清除参数

Posted

技术标签:

【中文标题】使用 `db.Database.SqlQuery<model>` 后如何清除参数【英文标题】:How to clear parameters after use of `db.Database.SqlQuery<model>` 【发布时间】:2016-11-04 08:07:25 【问题描述】:

在使用 Entity Framework 的 MVC 5 Web 应用程序中,我学习了如何通过使用 db.Database.SqlQuery&lt;model&gt; 来填充索引视图来执行存储过程并在索引视图中显示结果。

这是我的索引视图中的相关代码(它有效)。

// supply parameter values required by the stored procedure
object[] parameters = 
  new SqlParameter("@campus",SqlDbType.NVarChar,3) Value=vm.SelectedCampus,
  new SqlParameter("@date1",SqlDbType.DateTime) Value=Convert.ToDateTime(vm.SelectedStartDate),
  new SqlParameter("@date2",SqlDbType.DateTime) Value=Convert.ToDateTime(vm.SelectedEndDate)
;

// populate the list by calling the stored procedure and supplying parameters
IEnumerable<PerfOdomoeterDate> query =
  db.Database.SqlQuery<PerfOdomoeterDate>("PerfOdomoeterDate @campus, @date1, @date2",
      parameters).OrderBy(m => m.StudentName).ToList();

为了将该代码放入更好的上下文中,这里是整个 Index ActionResult。

private PerformanceContext db = new PerformanceContext();
private static readonly string d1 = DateTime.Now.ToShortDateString();
private static readonly string d2 = DateTime.Now.ToShortDateString();

[HttpGet]
public ActionResult Index(int? page, string SelectedCampus = "CRA", string SelectedStartDate=null, string SelectedEndDate=null)

  int PageNumber = (page ?? 1);

  PerfOdomoeterDateViewModel vm = new PerfOdomoeterDateViewModel();
  vm.SelectedCampus = SelectedCampus;

  vm.SelectedStartDate = string.IsNullOrEmpty(SelectedStartDate) ? d1 : SelectedStartDate;
  vm.SelectedEndDate = string.IsNullOrEmpty(SelectedEndDate) ? d2 :SelectedEndDate;
  vm.CampusList = StaticClasses.ListBank.CampusList();        

  // supply parameter values required by the stored procedure
  object[] parameters = 
      new SqlParameter("@campus",SqlDbType.NVarChar,3) Value=vm.SelectedCampus,
      new SqlParameter("@date1",SqlDbType.DateTime) Value=Convert.ToDateTime(vm.SelectedStartDate),
      new SqlParameter("@date2",SqlDbType.DateTime) Value=Convert.ToDateTime(vm.SelectedEndDate)
  ;

  // populate the list by calling the stored procedure and supplying parameters
  IEnumerable<PerfOdomoeterDate> query =
      db.Database.SqlQuery<PerfOdomoeterDate>("PerfOdomoeterDate @campus, @date1, @date2",
          parameters).OrderBy(m => m.StudentName).ToList();            

  vm.CreditTable = query.ToPagedList(PageNumber, 25);                        
  return View(vm);

正如我所说,此代码在索引视图中完美运行。但是,在一个单独的 ActionResult 中,用户可以选择将数据集导出到 Excel 文件,我使用相同的代码,我得到这个运行时错误:

SqlParameter 已被另一个 SqlParameterCollection 包含。

我的印象是每个 ActionResult 都在自己的范围内,那么当我从单独的 ActionResult 调用新查询时,我是怎么得到这个错误的?

Intellisense 没有给我任何线索,告诉我如何在执行存储过程后显式清空参数。

这是产生错误的 ActionResult 中的代码。

public ActionResult ExportToExcel(string SelectedCampus, string SelectedStartDate, string SelectedEndDate)
            

  object[] parameters2 = 
      new SqlParameter("@campus",SqlDbType.NVarChar,3) Value=SelectedCampus,
      new SqlParameter("@date1",SqlDbType.DateTime) Value=Convert.ToDateTime(SelectedStartDate),
      new SqlParameter("@date2",SqlDbType.DateTime) Value=Convert.ToDateTime(SelectedEndDate)
  ;

  IEnumerable<PerfOdomoeterDate> query =
      db.Database.SqlQuery<PerfOdomoeterDate>("PerfOdomoeterDate @campus, @date1, @date2",
          parameters2).OrderBy(m => m.StudentName).AsEnumerable();

...

【问题讨论】:

我在其他文章中看到了这个'command.Parameters.Clear()',但是我不知道在这种情况下如何应用它。我没有任何名为“命令”的东西,我无法通过 IntelliSense 导航找到它。 但是您以另一种方式进行了一些研究。我使用“重构”来提取 IEnumerable 查询语句,以便可以从任一 ActionResult 调用它。现在没有问题。因此,您可以获得功劳,您可能希望将其发布为答案。 【参考方案1】:

.Net 框架提供给我们的 ADO.Net 对象(如 SqlParameterSqlCommand 等)仅仅是由 .Net 连接池管理的真实内容之上的一层.如果我们创建一个新的SqlConnection——这由db.Database.SqlQuery 隐式完成——我们并没有真正建立到数据库的新连接。那太贵了。实际上,我们的连接对象“插入”到连接池中的可用连接。

通常,这种机制是相当透明的,但它会在您在此处看到的问题中公开。我记得曾经遇到过类似的问题(异常持续的时间比我们看到的要长)。

信息是:你不能打败它,所以加入它。快速解决方案似乎是在其中一种方法中重命名参数。当然,更好的解决方案是将代码的重复部分分解为包含相同部分的方法。

【讨论】:

以上是关于使用 `db.Database.SqlQuery<model>` 后如何清除参数的主要内容,如果未能解决你的问题,请参考以下文章

db.Database.SqlQuery 原始数据返回存储过程名称和参数

EF中使用SQL语句或存储过程

EF框架使用sql语句或存储过程

EF中使用SQL语句或存储过程

Ef执行Sql查询

在 var 数组中存储两个不同的对象?