ASP.NET CORE EF 中的辅助数据库上下文
Secondary Db Context in ASP.NET CORE EF
我有一个发送通知的服务,它需要一个数据库连接来查找订阅。我还有一个控制器(可能更多)执行一些逻辑并发送通知。
这个问题是,因为 DI 它使用 DbContext
的相同实例,所以我在相同的上下文中重新使用 DataReader
时抛出错误(可以理解)。
如果不在 DbConnectionString
中启用 MARS 标志,我真的很想这样做。鉴于控制器不能使用 .ToList()
或没有跟踪,并且 'inner' NotificationService
需要查找数据库 - 这甚至可能吗?
public class NotificationSystem
{
private readonly DbContext context;
public NotificationSystem(DbContext context) { this.context = context;}
public void SendNotification(string username){
var subscriptions = context.subscriptions.where(u => u.username == username);
// Do some notification stuff
}
}
还有一个简单的控制器
public class SendRemindersController : Controller
{
private readonly DbContext _context;
private readonly NotificationSystem _notificationSystem;
public SendRemindersController(DbContext context, NotificationSystem notificationSystem)
{
this._context = context;
this._notificationSystem = notificationSystem;
}
[HttpGet]
public async Task<IActionResult> Get()
{
var reminders = _context.Reminders.Where(r => r.Sent == false && r.RemindAt < DateTime.UtcNow);
foreach (var reminder in reminders)
{
await _notificationSystem.SendNotificationToUser(reminder.UserId);
reminder.Sent = true;
}
await _context.SaveChangesAsync();
return Ok();
}
}
和startup.cs
(是的,我知道我还没有使用过接口,稍后会重构)。
services.AddDbContext<DbContext>(options => options.UseSqlServer(connection));
services.AddTransient<NotificationSystem, NotificationSystem>();
更新
这个问题是有缺陷的,因为我误以为 .ToList/.ToArray 也从上下文中分离了实体。事实上,这些不会分离,只会执行查询。
这是因为您正在使用同一个 DbContext
来同时执行多个交易。如果你像这样将 .ToListAsync()
添加到这行代码
var reminders = await _context.Reminders
.Where(r => r.Sent == false && r.RemindAt < DateTime.UtcNow)
.ToListAsync();
它将立即检索所有提醒,然后循环内的代码(在此语句之后)可以使用 DbContext
而不会 DbContext
抛出异常,因为活动结果集仍在处理中迭代。
我有一个发送通知的服务,它需要一个数据库连接来查找订阅。我还有一个控制器(可能更多)执行一些逻辑并发送通知。
这个问题是,因为 DI 它使用 DbContext
的相同实例,所以我在相同的上下文中重新使用 DataReader
时抛出错误(可以理解)。
如果不在 DbConnectionString
中启用 MARS 标志,我真的很想这样做。鉴于控制器不能使用 .ToList()
或没有跟踪,并且 'inner' NotificationService
需要查找数据库 - 这甚至可能吗?
public class NotificationSystem
{
private readonly DbContext context;
public NotificationSystem(DbContext context) { this.context = context;}
public void SendNotification(string username){
var subscriptions = context.subscriptions.where(u => u.username == username);
// Do some notification stuff
}
}
还有一个简单的控制器
public class SendRemindersController : Controller
{
private readonly DbContext _context;
private readonly NotificationSystem _notificationSystem;
public SendRemindersController(DbContext context, NotificationSystem notificationSystem)
{
this._context = context;
this._notificationSystem = notificationSystem;
}
[HttpGet]
public async Task<IActionResult> Get()
{
var reminders = _context.Reminders.Where(r => r.Sent == false && r.RemindAt < DateTime.UtcNow);
foreach (var reminder in reminders)
{
await _notificationSystem.SendNotificationToUser(reminder.UserId);
reminder.Sent = true;
}
await _context.SaveChangesAsync();
return Ok();
}
}
和startup.cs
(是的,我知道我还没有使用过接口,稍后会重构)。
services.AddDbContext<DbContext>(options => options.UseSqlServer(connection));
services.AddTransient<NotificationSystem, NotificationSystem>();
更新
这个问题是有缺陷的,因为我误以为 .ToList/.ToArray 也从上下文中分离了实体。事实上,这些不会分离,只会执行查询。
这是因为您正在使用同一个 DbContext
来同时执行多个交易。如果你像这样将 .ToListAsync()
添加到这行代码
var reminders = await _context.Reminders
.Where(r => r.Sent == false && r.RemindAt < DateTime.UtcNow)
.ToListAsync();
它将立即检索所有提醒,然后循环内的代码(在此语句之后)可以使用 DbContext
而不会 DbContext
抛出异常,因为活动结果集仍在处理中迭代。