I have a service that sends notifications, it requires a db connection to lookup subscriptions. I also have a controller (and may more) that does some logic, and sends notifications.
The problem with this is, because of DI it uses the same instance of the DbContext so I get a error thrown for re-using a DataReader in the same context (understandable).
I would really love to do this without enabling the MARS flag in DbConnectionString. Given that the controllers cannot use .ToList() or no tracking and the 'inner' NotificationService needs to lookup the database - is this even possible?
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
}
}
And a simple controller
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();
}
}
And startup.cs (yes I know I haven't used an interface, that will get refactored later).
services.AddDbContext<DbContext>(options => options.UseSqlServer(connection));
services.AddTransient<NotificationSystem, NotificationSystem>();
Update
This question is flawed since i was under the false impression that .ToList/.ToArray also detached the entities from the context. In-fact these do not detach and only execute the query.
reminderfield, or ifSendNotificationToUseris trying to execute a query in the middle of the iteration. Make sure you load all required data when the operation starts, eg by using anInclude()statement.hierarchyid. Finding parents of a node is trivial this way. EF does support hierarchyid through an extension. This will increase your performance 100x at least (1 query for all parents instead of 3-4 recursions per item)