c# - 使用 EF Core 调用存储过程并关闭连接
问题描述
我有一个使用 EF Core 的 ASP.NET Core 2.2 应用程序。我有服务类,它通常DbContext
用于任何 CRUD 操作。但是,在其中一种方法(Assign
下面的方法)中,我需要使用存储过程。所以我使用下面的代码。请注意,它是作为实例DbContext
注入的。Scoped
public class MyService : IMyService
{
private readonly MyDbContext _dbContext;
public MyService(MyDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task<Employee> GetByID(int id)
{
return await _dbContext.Employees.FindById(id);
}
public async Task<int?> Assign(int itemID, int userID)
{
using (var cmd = _dbContext.Database.GetDbConnection().CreateCommand())
{
var p1 = new SqlParameter("@ItemId", SqlDbType.Int);
p1.Value = itemID;
var p2 = new SqlParameter("@UserID", SqlDbType.Int);
p2.Value = userID;
cmd.CommandText = "dbo.prcAssign";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(p1);
cmd.Parameters.Add(p2);
await _dbContext.Database.OpenConnectionAsync();
var result = await cmd.ExecuteScalarAsync();
if (result != null)
{
return Convert.ToInt32(result);
}
return null;
}
}
}
存储过程在内部使用 SQL 事务。我想知道我是否需要在Assign
方法中显式关闭数据库连接,或者连接会在请求端被容器自动关闭?
问题是由于存储过程正在使用事务,它在表上设置了读锁(我们实际上希望表上的读锁以避免获取脏数据)。存储过程需要几毫秒的时间来执行,我们几乎没有 50 个用户。然而,我们经常在Employee
桌子上遇到死锁:
System.Data.SqlClient.SqlException (0x80131904):事务(进程 ID 59)与另一个进程在锁资源上死锁,并已被选为死锁受害者。重新运行事务。
在 System.Data.SqlClient.SqlConnection.OnError(SqlException 异常,布尔 breakConnection,操作1 wrapCloseInAction) 在 System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject> stateObj,布尔调用者HasConnectionLock,布尔 asyncClose) 在 System.Data.SqlClient.TdsParser System.Data.SqlClient.SqlDataReader.TryConsumeMetaData () 处的.TryRun(RunBehavior runBehavior、SqlCommand cmdHandler、SqlDataReader dataStream、BulkCopySimpleResultSet bulkCopyHandler、TdsParserStateObject stateObj、Boolean&dataReady )1 wrapCloseInAction)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action
在 System.Data.SqlClient.SqlDataReader.get_MetaData()
在 System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
在 System.Data.SqlClient.SqlCommand.CompleteAsyncExecuteReader()
在 System.Data.SqlClient .SqlCommand.InternalEndExecuteReader(IAsyncResult asyncResult, String endMethod)
在 System.Data.SqlClient.SqlCommand.EndExecuteReaderInternal(IAsyncResult asyncResult)
在 System.Data.SqlClient.SqlCommand.EndExecuteReader(IAsyncResult asyncResult) > 在 System.Threading.Tasks.TaskFactory1.FromAsyncCoreLogic(IAsyncResult iar, Func
2 endFunction , Action1 endAction, Task
1 promise, Boolean requiresSynchronization)
--- 从先前抛出异常的位置结束堆栈跟踪 ---在 D:\xxxx\Services\MyService.cs:line 84 中的 xxxxx.Services.MyService.Assign(Int32 itemID, Int32 userID)
解决方案
我想知道我是否需要在
Assign
方法中显式关闭数据库连接,或者连接会在请求端被容器自动关闭?
连接是否会在以后自动关闭并不重要。遵循良好的编程实践,应该释放分配的资源(创建 -> 处置、打开 -> 关闭等)。
EF Core 内部正在为每个需要打开连接的操作执行此操作,因此您最好也这样做,例如像这样
await _dbContext.Database.OpenConnectionAsync();
try
{
var result = await cmd.ExecuteScalarAsync();
if (result != null)
{
return Convert.ToInt32(result);
}
return null;
}
finally
{
_dbContext.Database.CloseConnection();
}
推荐阅读
- python - 如何修复“ValueError:查看限制最小值 -36881.6 小于 1 并且是无效的 Matplotlib 日期值。”?
- angular - Angular 9 或 10 + Angular Material 10:导入无法解析为 NgModule 类
- pine-script - pow() 不适用于变量指数 1/N(第 N 个根)
- x86 - 如何编写一个引导扇区,从它所在的 USB 记忆棒读取数据?
- r - 在表函数中嵌入子集
- python - 查找具有所需范围内的值的连续行
- python - 用于查找两个时间戳变量之间差异的任何 Python 代码
- javascript - 如何在不使用分隔符(split())的情况下从字符串中获取数组,只是为了获取整个字符串并将其转换为数组类型?
- python - 如何在 Python 中组合两个不平衡列表中的两个字典?
- linux - docker容器在启动期间无法在卷挂载中打开符号链接文件