When to reuse data contexts - c#

I've been reading a bit of confusing and conflicting advice on this.
Given the following example methods:
using(var db = new MainContext())
{
var q = db.tblArcadeGames;
foreach (var game in q)
{
UpdateGameStats(game);
}
}
public void UpdateGameStats(ArcadeGame game)
{
using(var db = new MainContext())
{
// Do some queries and updates etc
}
}
Should the data context created initally be passed as a parameter to UpdateGameStats as follows:
using(var db = new MainContext())
{
var q = db.tblArcadeGames;
foreach (var game in q)
{
UpdateGameStats(game, db);
}
}
public void UpdateGameStats(ArcadeGame game, MainContext db)
{
// Do some queries and updates etc
}
Is reusing a data context always best practise? Should only one be created on each page which is reused? Or should a new one be created each time?
Reusing data contexts appears to me to create a situation where it's harder to maintain and modularise code in some instances.

In this specific example, I'd reuse the data context:
Avoids overhead of establishing a new context
Keeps entities attached, which is good if you plan on reusing them on the page
There isn't a hard, fast rule on when to dispose of your contexts. It more depends on how you're using your data:
Rarely: if your operations are small, infrequent, and atomic, keeping a context alive might introduce more overhead/maintenance than creating one on demand. Just put it in a using.
Normal: if you're updating and saving on a regular basis, make a context per page, but have the page dispose it instead of passing it around. Gives the best tradeoff of performance and maintainability.

You should reuse the data context instance as long as you are reusing the entities. Since the entities are attached to a specific context, you should keep using the same context between query and update.
My personal preference for web application is to use a single data context for the duration of the request and dispose it in EndRequest event.

Related

Entity Framework - concurrent use of containers

In the Business Logic Layer of an Entity Framework-based application, all methods acting on DB should (as I've heard) be included within:
using(FunkyContainer fc = new FunkyContainer())
{
// do the thing
fc.SaveChanges();
}
Of course, for my own convenience often times those methods use each other, for the sake of not repeating myself. The risk I see here is the following:
public void MainMethod()
{
using(FunkyContainer fc = new FunkyContainer())
{
// perform some operations on fc
// modify a few objects downloaded from DB
int x = HelperMethod();
// act on fc again
fc.SaveChanges();
}
}
public int HelperMethod()
{
using(FunkyContainer fc2 = new FunkyContainer())
{
// act on fc2 an then:
fc2.SaveChanges();
return 42;
}
}
I doesn't look good to me, when the container fc2 is created, while fc is still open and has not been saved yet. So this leads to my question number one:
Is having multiple containers open at the same time and acting on them carelessly an acceptable practice?
I came to a conclusion, that I could write a simple guard-styled object like this:
public sealed class FunkyContainerAccessGuard : IDisposable
{
private static FunkyContainer GlobalContainer { get; private set; }
public FunkyContainer Container // simply a non-static adapter for syntactic convenience
{
get
{
return GlobalContainer;
}
}
private bool IsRootOfHierarchy { get; set; }
public FunkyContainerAccessGuard()
{
IsRootOfHierarchy = (GlobalContainer == null);
if (IsRootOfHierarchy)
GlobalContainer = new FunkyContainer();
}
public void Dispose()
{
if (IsRootOfHierarchy)
{
GlobalContainer.Dispose();
GlobalContainer = null;
}
}
}
Now the usage would be as following:
public void MainMethod()
{
using(FunkyContainerAccessGuard guard = new FunkyContainerAccessGuard())
{
FunkyContainer fc = guard.Container;
// do anything with fc
int x = HelperMethod();
fc.SaveChanges();
}
}
public int HelperMethod()
{
using(FunkyContainerAccessGuard guard = new FunkyContainerAccessGuard())
{
FunkyContainer fc2 = guard.Container;
// do anything with fc2
fc2.SaveChanges();
}
}
When the HelperMethod is called by MainMethod, the GlobalContainer is already created, and its used by both methods, so there is no conflict. Moreover, HelperMethod can be also used separately, and then it creates its own container.
However, this seems like a massive overkill to me; so:
Has this problem been already solved in form of some class (IoC?) or at least some nice design pattern?
Thank you.
Is having multiple containers open at the same time and acting on them carelessly an acceptable practice?
Generally this is perfectly acceptable, sometimes even necessary, but you have to be caucious with that. To have multiple containers at the same time is especially handy when doing multithreading operations. Because of how db works generally each thread should have its own DbContext that should not be shared with other threads. Downside to using multiple DbContext at the same time is that each of them will use separate db connection, and sometimes they are limited, what may lead to application occasionally being unable to connect to database. Other downside is the fact that entity generated by one DbContext may not be used with entity generated by other DbContext. In your example HelperMethod returns primitive type, so this is perfectly safe, but if it would return some entity object that in MainMethod you would like to assign for instance to some navigation property of entity created by MainMethod DbContext then you will receive an exception. To overcome this in MainMethod you would have to use Id of entity returned by HelperMethod to retrieve that entity once more, this time with fc context. On the other hand there is an advantage of using multiple contexts - if one context have some troubles, for instance it tried to save something that violated index constaint, then all next trials of saving changes will result in the same exception as the faulty change will still be pending. If you use multiple DbContexts then if one would fail, then second will operate independently - this is why DbContexts should not live long. So generally I would say the best usage rule would be:
Each thread should use a separate DbContext
All methods that executes on the same thread should share the same DbContext
Of course the above applies if the job to be done is short. DbContext should not live long. The best example would be web applications - there each server request is handled by separate thread and the operations to generate response generally do not take long. In such case all methods executed to generate one response should share for convenience the same DbContext. But each request should be served by separate DbContext.
Has this problem been already solved in form of some class (IoC?) or at least some nice design pattern?
What you need to assure is that your DbContext class is singleton per thread, but each thread has its own instance of that class. In my opinion best way to assure this is with IoC. For instance in Autofac in web applications I register my DbContext with the following rule:
builder
.RegisterType<MyDbContext>()
.InstancePerHttpRequest();
This way autofac IoC generates one DbContext per request and share existing instance within the request serving thread. You do not need to care here for disposing your DbContext. Your IoC will do this when your thread is over.
Working in multiple connections at the same time is not the right approach most of the time because:
You can get distributed deadlocks that SQL Server cannot resolve.
You might not see data that was previously written but not yet committed.
You can't share entities across context boundaries (here: methods).
More resource usage.
No ability to transact across context boundaries (here: methods).
These are very severe disadvantages. Usually, the best model is to have one context, connection and transaction for the request that the app is processing (HTTP or WCF request). That's very simple to set up and avoids a lot of issues.
EF is supposed to be used as a live object model. Do not cripple it by reducing it to CRUD.
static FunkyContainer GlobalContainer
That does not work. You shouldn't share a context across requests. Super dangerous. Consider storing a context in HttpContext.Items or whatever is the per-request store in your app.

Keep one common DataContext per DAL instead of create it for each database call?

In my DALs I currently use a new DataContext instance for each method, i.e. create the context for each data call, then dispose it (with using). I remember I read that was sort of a best practice.
Now I think that I probably better use one common DataContext per DAL which will require less lines to write and will allow to update changes in the database without attaching the entities to the newly created context.
But I am not sure whether this will impact the productivity of the application. Are there negative things which may appear with this new approach, like maybe "each context reserves a connection line with a database" or "there are only a limited number of contexts available per application"?
From what I read and my own conclusion, the basic rule is: use a single DataContext instance for each short time set of operations, this means:
Use new (separate) instance of DataContext for each operation (transaction) in long living parent objects, such as DALs. For example, the main form has a DAL which uses a DataContext, the main form is the most long living object in a desktop application, thus having a single instance of a DataContext to serve all the main form data operations will not be a good solution due to the increasing cache and risk of the data to become obsolete.
Use single (common) instance of DataContext for all operations in short time living parent objects. For example, if we have a class which executes a set of data operations in a short amount of time, such as takes data from a database, operates with them, updates them, saves the changes to the database and gets disposed, we better create one single instance of the DataContext and use it in all the DAL methods. This relates to a web applications and services as well since they are stateless and are being executed per request.
Example of when I see a requirement of a common DataContext:
DAL:
// Common DAL DataContext field.
DataContext Context = new DataContext();
public IEnumerable<Record> GetRecords()
{
var records = Context.Records;
foreach (var record in records)
{
yield return record;
}
}
public void UpdateData()
{
Context.SaveChanges();
}
BLL:
public void ManageData()
{
foreach (var record in DAL.GetRecords())
{
record.IsUpdated = true;
DAL.UpdateData();
}
}
With this approach you will end up with a lot of objects created in memory (potentially, the whole db) and (which can be even more important), those objects will not correspond to current values in the db (if the db gets updated outside of your application/machine). So, in order to use memory efficiently and to have up-to-data values for your entities, it's really better to create data context per transaction.

Does it make sense to create new object in Entity Framework before saving it to resolve problems with multiple Contexts?

Does it make sense to create new object before trying to save object that I already have loaded but with more then one Context?
After lots of tries and errors this code seems to work fine. Basically it's regetting values for Konsultanci and Szkolenie with the current Context based on objects that are read from ObjectListView.
var listaDoPodmiany = new List<SzkolenieUczestnicy>();
if (listaUczestnikow.GetItemCount() > 0) {
foreach (SzkolenieUczestnicy currentUczestnik in listaUczestnikow.Objects) {
using (var context = new EntityBazaCRM(Settings.sqlDataConnectionDetailsCRM)) {
if (currentUczestnik.SzkolenieUczestnicyID == 0) {
var nowy = new SzkolenieUczestnicy {
Konsultanci = context.Konsultancis.First(p => p.KonsultantNazwa == currentUczestnik.Konsultanci.KonsultantNazwa),
Szkolenie = context.Szkolenies.First(p => p.SzkolenieID == varSzkolenie.SzkolenieID),
SzkolenieUzytkownik = currentUczestnik.SzkolenieUzytkownik,
SzkolenieUzytkownikData = currentUczestnik.SzkolenieUzytkownikData,
UczestnikPotwierdzilUdzial = currentUczestnik.UczestnikPotwierdzilUdzial,
UczestnikPrzybyl = currentUczestnik.UczestnikPrzybyl
};
context.SzkolenieUczestnicies.AddObject(nowy);
context.SaveChanges();
listaDoPodmiany.Add(nowy);
} else {
context.SzkolenieUczestnicies.Attach(currentUczestnik);
context.ObjectStateManager.ChangeObjectState(currentUczestnik, EntityState.Modified);
context.SaveChanges();
listaDoPodmiany.Add(currentUczestnik);
}
}
}
listaUczestnikow.ClearObjects();
listaUczestnikow.SetObjects(listaDoPodmiany);
}
This seems to solve lots of problems I was getting about multiple contexts. But is it good approach? Will there be much impact on speed since I guess Konsultanci and Szkolenie will be read another time from SQL?
This is continuation (or more like conclusion from multiple questions I asked before):
The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects
Can context of Entity Framework be extracted from object later on?
Can Entity Framework context be reused all the time in code?
Does it make sense to create new object before trying to save object
that I already have loaded but with more then one Context?
No. But it shows you have a design problem in your application. You shouldn't have to deal with multiple contexts for the same objects.
I think you have a problem with your contexts lifetime. This isn't an easy issue to solve, but here is an article that could help you. See also here.
My opinion is that contexts should have the shortest lifetime as possible. Long-running contexts are generally a bad practice, as you'll quickly encounter issues in your application (memory leak, problems when dealing with multi-threading or concurrency...etc.)
If you have a 3-tiers architecture, then you really should expose stateless services and create a new context per request. If you're accessing directly the database from your application (2-tiers application), for instance a Winform application that requests the DB directly, shorten the lifetime of your context as much as possible if you can't do stateless requests.
Final word: creating new contexts has a very small overhead, and it won't lead to performance issues 99% of the time.

Can Entity Framework context be reused all the time in code?

In this question I was having problem with saving objects that had foreign keys because Objects were build from multiple Objects connected to each other thru foreign keys but they were loaded using different context each time. For example:
using (var context = new EntityBazaCRM(Settings.sqlDataConnectionDetailsCRM)) {
IQueryable<Konsultanci> listaKonsultantow = from k in context.Konsultancis
select k;
}
Then somewhere else in the code there would be more context used to get more object types like Persons, Training, you name it.
Then there would be code to save it (simplified):
using (var context = new EntityBazaCRM(Settings.sqlDataConnectionDetailsCRM)) {
if (context.Szkolenies.Any(t => t.SzkolenieID == currentSzkolenie.SzkolenieID)) {
context.Szkolenies.Attach(currentSzkolenie);
context.ObjectStateManager.ChangeObjectState(currentSzkolenie, EntityState.Modified);
} else {
context.Szkolenies.AddObject(currentSzkolenie);
}
context.SaveChanges();
}
Usually after trying to save it there would be multiple error messages
An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.
or
The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects
and few others.
So to resolve it I have declared private EntityBazaCRM context = new EntityBazaCRM(Settings.sqlDataConnectionDetailsCRM); on top of my class and reused it all the time without putting it into using. Thanks to this action I didn't have to attach anything prior to saving or anything. I was just using same context and attached any foreign keys I wanted using currentUczestnik.Szkolenie = szkolenie; and currentUczestnik.Konsultanci = consultants;. It saved without problems.
To the question:
It works for a small GUI that I have now that isn't overcomplicated. But what if I introduce multithreading, try to get multiple values from all over the place for different objects (load object to GUI, to ListView etc) using the same Context? Won't it blow back on me hurting me severely ?
In my old code before I found out about Entity Framework I was using:
const string preparedCommand = #"SELECT ID FROM TABLE WHERE NAME = "TEST"";
using (SqlConnection varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetails))
using (var sqlQuery = new SqlCommand(preparedCommand, varConnection))
using (SqlDataReader sqlQueryResult = sqlQuery.ExecuteReader())
while (sqlQueryResult.Read()) {
string id= sqlQueryResult["id"].ToString();
}
}
which basically I was using for every single time I wanted to connect to SQL. If there was no connection, it would be established, if there was connection it would be reused and no problems with multithreading.
Can someone tell me what problems I can expect from doing it the way I found out to be working? Or maybe it's best way to do it?
But what if I introduce multithreading, try to get multiple values
from all over the place for different objects (load object to GUI, to
ListView etc) using the same Context? Won't it blow back on me hurting
me severely ?
Yes, yes it will. A context is basically a thin layer on top of a database connection - which is not thread safe, so you cannot reuse the same context across threads. What you are looking for is a unit of work within which you use the same context, but once that unit of work is completed you dispose the context. Since you use your own repository implementation you will have to build the unit of work on top of those repositories.

LINQ to SQL: Reusing DataContext

I have a number of static methods that perform simple operations like insert or delete a record. All these methods follow this template of using:
public static UserDataModel FromEmail(string email)
{
using (var db = new MyWebAppDataContext())
{
db.ObjectTrackingEnabled = false;
return (from u in db.UserDataModels
where u.Email == email
select u).Single();
}
}
I also have a few methods that need to perform multiple operations that use a DataContext:
public static UserPreferencesDataModel Preferences(string email)
{
return UserDataModel.Preferences(UserDataModel.FromEmail(email));
}
private static UserPreferencesViewModel Preferences(UserDataModel user)
{
using(var db = new MyWebAppDataContext())
{
var preferences = (from u in db.UserDataModels
where u == user
select u.Preferences).Single();
return new UserPreferencesViewModel(preferences);
}
}
I like that I can divide simple operations into faux-stored procedures in my data models with static methods like FromEmail(), but I'm concerned about the cost of having Preferences() invoking two connections (right?) via the two using DataContext statements.
Do I need to be? Is what I'm doing less efficient than using a single using(var db = new MyWebAppDataContext()) statement?
If you examine those "two" operations, you might see that they could be performed in 1 database roundtrip. Minimizing database roundtrips is a major performance objective (second to minimizing database io).
If you have multiple datacontexts, they view the same record differently. Normally, ObjectTracking requires that the same instance is always used to represent a single record. If you have 2 DataContexts, they each do their own object tracking on their own instances.
Suppose the record changes between DC1 observing it and and DC2 observing it. In this case, the record will not only have 2 different instances, but those different instances will have different values. It can be very challenging to express business logic against such a moving target.
You should definately retire the DataContext after the UnitOfWork, to protect yourself from stale instances of records.
Normally you should use one context for one logical unit of work. So have a look at the unit of work pattern, ex. http://dotnet.dzone.com/news/using-unit-work-pattern-entity
Of cause there is some overhead in creating a new DataContext each time. But its a good practice to do as Ludwig stated: One context per unit of work.
Its using connection pooling so its not a too expensive operation.
I also think creating a new DataContext each time is the correct way but this link explains different approaches for handling the data context. Linq to SQL DataContext Lifetime Management
I developed a wrapper component that uses an interface like:
public interface IContextCacher {
DataContext GetFromCache();
void SaveToCache(DataContext ctx);
}
And use a wrapper to instantiate the context; if it exists in cache, it's pulled from there, otherwise, a new instance is created and pushed to the Save method, and all future implementations would get the value from the getter.
Depending on the type of application would be the actual caching mechanism. Say for instance, an ASP.NET web application. This could store the context in the items collection, so its alive for the request only. For a windows app, it could pull it from some singleton collection. It could be whatever you wanted under the scenes.

Categories