Any difference between using the default DbContext vs SpecificDbContext as service dependency? - c#

We use multiple micro-service applications, each with it's own specific DbContext. Few entities are duplicated in all of those contexts by necessity, for example - the Region entity. I want to use a single service to perform CRUD on Regions in all db contexts. That's why I've used the default DbContext as dependency in this service, relying on the IoC container in each micro-service app to provide it's own specific, let's call it ExampleDbContext. Then I use Set<Region> to manipulate the entity.
I get an inconsistent behavior - sometimes it works, while most of the time I get:
InvalidOperationException: An attempt was made to use the context while it is being configured. A
DbContext instance cannot be used inside OnConfiguring since it is
still being configured at this point. This can happen if a second
operation is started on this context before a previous operation
completed...
From what I can gather the default culprit is simultaneous usage of the same DbContext instance. All our methods are async so it is certainly possible, but I find it unlikely, since the code that throws is called once on the application start inside the Program.Main method. Either way, I am not sure how to confirm it or rule that out.
What I find strange about this is that if I replace DbContext with an explicit ExampleDbContext this error is no longer thrown. Thus I am lead to believe that there is some difference in how the default DbContext is instantiated.
As a further note I think that ExampleDbContext is instantiated 3 times, because a breakpoint inside it's OnConfiguring method gets hit 3 times.
Edit
Turns out using the specific ExampleDbContext also throws, however much more rarely.
Edit 2
Alright, after another day debugging and commenting out code to pin-point the issue, I can confirm that it was indeed parallel calls to the same DbContextinstance.
One piece is still still missing from the puzzle:
- Why using DbContext instead of ExampleDbContext threw more frequently?
Overall I guess the moral of the story is "Take your time to eliminate the obvious cause of the issue". When that's off the tables think about other causes and only then post about asking help.

Related

How to properly implement DbCommandInterceptor with per-DbContext state?

I am following Tom Dykstra's Getting Started with Entity Framework 6 Code First using MVC 5 tutorial. Part 4 of this tutorial covers EF6's connection resiliency and command interception features.
As a way of demonstrating the use of command interception, the tutorial provides two example DbCommandInterceptor implementations. One (SchoolInterceptorLogging) interfaces with a logger to record each SQL command that is executed, how much time it took to execute, and whether there was an exception. The other example (SchoolInterceptorTransientErrors) simulates transient DB errors so that connection resiliency can be tested.
Although the tutorial does not specifically mention the issue of synchronization, I assume that because a single instance of the DbCommandInterceptor is registered via DbInterception.Add(), that any per-DbContext state utilized by the DbCommandInterceptor must be synchronized. For example, SchoolInterceptorLogging should probably synchronize use of the _stopwatch, and SchoolInterceptorTransientErrors should probably synchronize the _counter.
I thought about using thread-local storage via ThreadStaticAttribute or ThreadLocal<T>. However, I am not sure that this is sufficient. Suppose that my application uses DbContext.SaveChangesAsync() to asynchronously save all changes. Isn't it possible for the same thread to handle two asynchronous save operations? If so, then thread-local storage wouldn't work.
Another idea is to store per-DbContext state in the call context. However, when using the CallContext, it is recommended that only immutable types should be used. (See Stephen Cleary's blog post, Implicit Async Context ("AsyncLocal").)
A third idea is to use a ConcurrentDictionary where the keys are the DbCommandInterceptionContext object passed to NonQueryExecuting()/NonQueryExecuted(), ReaderExecuting()/ReaderExecuted(), or ScalarExecuting()/ScalarExecuted(), and the values are a state object. However, I have two questions about this approach:
Is the DbCommandInterceptionContext object that is passed to the *Executing()/*Executed() method distinct for each save operation?
From setting a breakpoint in ReaderExecuting() and calling GetHashCode() on the interception context object, it appears to be distinct for each retry let alone save operation (tested EntityFramework version 6.1.3).
Will the *Executed() method always be called?
This is to make sure that anything added to the ConcurrentDictionary in the *Executing() method can always be cleaned up by the *Executed() method.
So, how should a DbCommandInterceptor with per-DbContext state be implemented?

MVVM light application - how to properly clean ViewModels

I am working on a cookbook window application in WPF which consist of one window and several userControls that are replacing each other with relayCommands using messages from MVVM Light.
The application works with a DB that is generated from the entityFramework. The problem that occurs after all but the first execution of the file is that the program shows many warings and errors such as this one:
Warning 1 Could not copy "...\cookbook\Cookbook.Services\Database1.mdf" to "bin\Debug\Database1.mdf". Beginning retry 1 in 1000ms. The process cannot access the file '...\cookbook\Cookbook.Services\Database1.mdf' because it is being used by another process. Cookbook.Services
In the ViewModelLocator I have this:
public ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<MainWindowViewModel>();
SimpleIoc.Default.Register<MainViewModel>();
SimpleIoc.Default.Register<FoodTypeViewModel>();
SimpleIoc.Default.Register<ShoppingCartViewModel>();
SimpleIoc.Default.Register<MenuViewModel>();
SimpleIoc.Default.Register<MenuListViewModel>();
SimpleIoc.Default.Register<MenuCalendarViewModel>();
SimpleIoc.Default.Register<ChooseFoodWindowViewModel>();
}
And also messages I am using to switch the userControls are creating new instances of ViewModels, such as:
BackToMainCommand = new RelayCommand(() =>
{
Messenger.Default.Send<ViewModelBase>(new MainViewModel());
},
() => true);
I have toyed with the ViewModels to make them singleton to make sure there are only single copies in the system, but SimpleIoc needs public constructors for registering. And also I don't know if that would even help my problem. Also what I didn't tell you is that the ViewModelLocator is used only in xaml so I don't even have its instance to clean the stuff. (I am probably using it wrong but I don't know how it should be used)
The problem is that I don't know how and where to clean all the ViewModels since they are beying created on many places I've mentioned and some of them are probably holding the *.mdf file.
As mentioned in the comments, you are getting the
Warning 1 Could not copy "...\cookbook\Cookbook.Services\Database1.mdf" to "bin\Debug\Database1.mdf". Beginning retry 1 in 1000ms.
The process cannot access the file '...\cookbook\Cookbook.Services\Database1.mdf' because it is being used by another process. Cookbook.Services
warning (and after sufficient retries error) message from the compiler in a build because, the process created for application that you were running/debugging:
has not yet completed, or
not closed all connections to the database file.
So when you build it again, its file handle is still open and you cannot copy over the open file.
It is difficult to establish from the code you have posted in your question what the direct cause of this is, but this line:
Messenger.Default.Send<ViewModelBase>(new MainViewModel());
clearly is problematic, because it returns a new instance, instead of the singleton lifecycle instance from the SimpleIoC container. Although still ugly from a proper DI perspective, you could change it to:
Messenger.Default.Send<ViewModelBase>(ServiceLocator.Current.GetInstance<MainViewModel>());
So it will not create a new instance of your MainViewModel, but return the one from the IoC container.
Furthermore, you may want to make sure that your database context is registered in your container, and injected into the view models that need it. Illustrating this (assuming your database context/service class is called MyDbContext, implements IMyDbContext, and takes a connection string as its constructor argument):
SimpleIoc.Default.Register<IMyDbContext>(() => new MyDbContext(GetMyConnectionString()));
Now, you must also ensure that on application exit, proper cleanup is performed so that Dispose is called on the IMyDbContext instance, and any other potential resources in your application that require disposal. If this is not already done, through MVVM Light, you can do that by reacting to the Application.Exit Event on your Application:
Your problem is probably caused by the way you use your DbContext. You did not present in your question how you handle so I will try to guess what happens on your side. You should always make sure that after using DbContext you immediately dispose it. It should not be kept for the whole application living time. I do not see that you are registering it with your IoC so I assume you just instantiates it somewhere within your ViewModels. In such case you should always have your DbContext objects within using() to assure they are disposed. If you will fullfil that you certainly should not have any connection open to your db when you close your application in ordinary way.
The other case is connected to debugging your application in VS. It is done by default with VS hosting process, so when you hit "stop debugging" button DbContexts with opened connections are not disposed and VS hosting process is not killed. To avoid such situations I would recommend you to try to disable VS hosting process. You can set it in project properties -> Debug -> and uncheck Enable the Visual Studio hosting process. However this may lower down a bit time in which your application starts to run when you debug it.

Should the DbContext in EF have a short life span?

I have a few long running tasks on my server. Basically they are like scheduled tasks - they run from time to time.
They all required access to the DB and I use Entity Framework for that. Each task uses a DbContext for access.
Should the DbContext object be recreated on every run or should I reuse it?
I should say "it depends" as there are probably scenarios where both answers are valid, however the most reasonable answer is "the context should be disposed as soon as it is not needed" which in practice means "dispose rather sooner than later".
The risk that comes from such answer is that newcomers sometimes conclude that the context should be disposed as otfen as possible which sometimes lead to a code I review where there are consecutive "usings" that create a context, use it for one or two operations, dispose and then another context comes up next line. This is of course not recommended also.
In case of web apps, the natural lifecycle is connected with a lifecycle of web requests. In case of system services / other long running applications one of lifecycle strategies is "per business process instance" / "per usecase instance" where business processing / use case implementations define natural borders where separate instances of contexts make sense.
Yes, DbContext should only live for a very short time. It is effectively your unit of work
You should definitely create it each time you're going to use it. (Well, you should inject it but that's another discussion :-))
Update : OK, I accept that 'create it each time you're going to use it' could be misleading. I'm so used to context being an instance on a class that is injected and so lives only for the life of a request that I struggle to think of it any other way... #wiktor's answer is definitely better as it more correctly expresses the idea that you should "dispose sooner rather than later"

Using EntityFramework in C# when using Entities for a long time

I'm struggling with the following problem.
I have a database with a table Jobs, which contains information about Jobs to be done. I followed the Code First approach of EF 6.0 and create a POCO class called Job. I then query the database for the Jobs:
DbSet<Job> receivedJobs;
using (var context = new MyContext())
{
receivedJobs = (from j in context.Jobs
select j);
}
With the received set receivedJobs I will then do a time consuming optimization.
As I understand it, the lifetime of the context as well as the resources the context controls ends with the closing bracket of the using statement. Also a good design should free resources to the database as soon as it is no longer required.
My question is now what should I do in my case? Just keep the database context alive until I finished my time consuming optimisation task. Or close the connection as it is not needed until the optimisation ends. But in the latter case what do I do with the disposed Job objects, because I will then need to access some navigation properties of them which I can't because the context was closed. (And by the way the data in the instances of the Job class will not be changed by the optimization. So it is not required to keep track of changes to these objects, because there will be none)
Hope someone can help me to understand what is the recommended design in this case.
Best regards
You should always hold a context for the least amount of time necessary to do the operations. In your case, it sounds like you will need the context until the optimization is done because you are using some of its methods for navigating the result set. If that is the case, then the context should be held until you don't need it.
The bad habit to avoid is to hold onto a context when you have no immediate need for it. You will see some applications that wrongly create a context on application start and hold it for the life of the application. That is bad and a waste of resources.
In your case, put the optimization code in place, use the context until the code is completed, then release the context. Your using statement will take care of all the messy disposal stuff. Just get your code that needs the context in the {} for the using and you should be good to go.
Altough it will not solve all of your issues, specially the design ones,do you know the "Include" function which preloads the navigation properties of you jobs?
For example if a job points to a list of Tasks thanks to property named "Tasks":
context.Jobs.Include("Tasks") //will preload the Tasks property of
your job.
context.Jobs.Include("Tasks.AllowedUsers") //will preload the Tasks
property of your job, and the AllowedUsers list of each task.
If you want to preload several properties at same level, just use something like:
context.Jobs.Include("Tasks").Include("OtherTasksOnJob")

Why isn't my ILoadEventListener being called?

I made a class that implements ILoadEventListener, and implemented an OnLoad() method (of course -- else it wouldn't even compile). After creating the "new NHibernate.Cfg.Configuration()", I add it as the documentation says:
configuration.EventListeners.LoadEventListeners = new ILoadEventListener[] {
new MyListener(),
new NHibernate.Event.Default.DefaultLoadEventListener()
};
However, it never seems to get called -- I've added logging statements to my OnLoad() and set a breakpoint there in the debugger -- even when using my app in a way that clearly gets objects from the database using this NHibernate session factory.
What am I missing?
EDIT: I poked around in the source code (the NHibernate event documentation is rather sparse), and found that the event that corresponds to IInterceptor is actually PreLoad, not Load, so I tried using that, and that one does fire. So I can use that for now, but I still don't really know what preload/load/postload are intended to be.
The documentation on this is practically nonexistent, so maybe this will help a few people:
None of the Load events (Load/PreLoad/PostLoad) will ever fire on an entity that is in the identity cache, even if you Get, Load, or query for it again.
This sort of makes sense if you squint at it just the right way, but it makes for a great deal of frustration due to non-deterministic behaviour, since most of the time, you won't know whether or not an entity is in the cache. Evidently, these events refer to the process of hydrating an entity as opposed to simply requesting it.
I haven't tested this theory, but I wouldn't be surprised if cache hits from the L2 cache also don't fire Load events, since those entities won't be hydrated either.
In practice, this means that if you want a particular listener to run on "every" entity, you need to account for the possibility that it was originally a transient instance which was introduced to the session by Save, Update, etc. In other words, if you implement IPostLoadEventListener, you probably also want to implement IPostInsertEventListener and IPostUpdateEventListener.
This won't actually change the behaviour - the listener will still only ever run the very first time an entity becomes associated with the session - but at least this guarantees that every entity you can retrieve from the session has been intercepted by that listener. In my case, I was trying to use PostLoad to inject something into the entity, so this was an acceptable workaround.
If you really need the listener to fire every time an entity is retrieved, you either need to use a stateless session (no cache) or evict the entities before loading/querying again.

Categories

Resources