1

I have my services configured and available via dependency injection. What I try to do is to get one at runtime (that's why I'm looking non-standard way). That means - not in a constructor, not hardcoded, I need to get a service dynamically exactly when it's needed.

Why? Entity Framework (Core). Well, version 3.1 doesn't have any means to reset the data context. Yesterday I found out that if I try to remove entry blocked by foreign key constraint - the context breaks irreversibly. The EF tries to save invalid changes each time, despite the first try failed. Using Database.RollbackTransaction doesn't help. Nothing does.

EF has more ugly "features", like default sandbox mode, where the context sees only its own changes, ignoring all external changes to the database. Like someone just thought "databases are primary single user, right?".

Anyway, no way of refreshing / reloading context in EF Core 3.1, failed write to database irreversibly breaks the context.

The way around this is to recreate the context when it needs to be refreshed / reset. That means I need to dispose the old context and create a new one.

I thought that configuring the data context service as Transient would achieve just that. Well - not exactly. I tried to remove an entry I couldn't remove, it failed and the only way I could do any successful write to the database was to reload the Blazor page.

I think of a solution like this:

DataContext.Database.BeginTransaction();
try {
    // some writing to the data context
    DataContext.Database.CommitTransaction();
} catch {
    DataContext.Database.RollbackTransaction();
    DataContext.Dispose();
    DataContext = GetService<MyDataContext>();
}

So I wonder how to get the service other then store IApplicationBuilder in a static property.

What's wrong with calling the constructor? The constructor requires options (like the connection string), so I would need the configuration service anyway. There are other ugly hacks to get the configuration at runtime, but come on, there must be another, better and just more sane way of doing it.

Harry
  • 4,524
  • 4
  • 42
  • 81
  • 1
    [Can you clear the failed operations?](https://stackoverflow.com/questions/259219/how-can-i-reject-all-changes-in-a-linq-to-sqls-datacontext) – ProgrammingLlama Jun 04 '20 at 07:19
  • @John The linked answer doesn't work with .NET Core 3.1. The developers did all they could to make fixing the problem completely impossible. So, with the new `ChangeTracker` property you can only accept changes, or accept changes, or... accept changes. No option to clear them. – Harry Jun 04 '20 at 08:12
  • @John Yes, I read all the answers and comments. This again shows how much crippled the EF Core 3.1 is. There is one recurring (and upvoted) answer: delete the context, create a new one. Now it seems like the only option left. Old EF had a refresh option. The new one doesn't. The old one had an option to reject changes. The new one doesn't. I solved the issue of foreign keys by just querying for related entries before calling remove, and external changes by just telling users to refresh the page manually often :/ Suboptimal workarounds. – Harry Jun 04 '20 at 08:27
  • Understood. Hopefully Microsoft will improve that. Personally I'd register a factory (`Func`) with the DI container and resolve that in the controller in order to generate new contexts, although I'm not sure if that works with EF or not - I'm just speaking from a general DI perspective. – ProgrammingLlama Jun 04 '20 at 08:36
  • 1
    @John I see we think alike ;) That's the workaround I was thinking of for a while. Well, I'll try it then. Thanks. – Harry Jun 04 '20 at 08:48
  • 1
    @John I found something better: https://stackoverflow.com/a/17967959/126537 - this actually works in EF Core 3.1. So no need to recreate the context for now. – Harry Jun 04 '20 at 09:00
  • Nice one! :) Glad you found a solution. – ProgrammingLlama Jun 04 '20 at 09:02

0 Answers0