【发布时间】:2016-10-17 12:03:28
【问题描述】:
我有一个发送通知的服务,它需要一个数据库连接来查找订阅。我还有一个控制器(可能更多),它执行一些逻辑并发送通知。
这个问题是,因为DI 它使用DbContext 的相同实例,所以在相同的上下文中重新使用DataReader 时会抛出错误(可以理解)。
我真的很想在不启用 DbConnectionString 中的 MARS 标志的情况下执行此操作。鉴于控制器不能使用.ToList() 或没有跟踪并且“内部”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 也将实体与上下文分离。事实上,这些不会分离,只会执行查询。
【问题讨论】:
-
如果您对
reminder字段使用延迟初始化,或者SendNotificationToUser试图在迭代中间执行查询,则会出现此错误。确保在操作开始时加载所有必需的数据,例如使用Include()语句。 -
顺便说一句,您应该有一个从提醒到用户或订阅的关系,而不是使用像用户名这样的 ID 来链接它们。
-
@PanagiotisKanavos 在实际代码中有:) 我只是想举个例子。
-
在这种情况下,您不需要第二次查询。你可以走的关系。在任何情况下,您都应该尝试在开始时加载所需的所有数据,以避免此错误和多次往返数据库
-
这是数据库的工作,例如
hierarchyid。以这种方式查找节点的父节点是微不足道的。 EF 通过an extension 支持hierarchyid。这将使您的性能至少提高 100 倍(对所有父母进行 1 次查询,而不是每个项目 3-4 次递归)
标签: c# asp.net entity-framework .net-core