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

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.

Related

When to reuse data contexts

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.

Attaching vs selecting and modifying in L2S

I have a Data Access Layer which creates a context and retrieves data (with no object tracking) and passes the information back to UI layer:-
My unit of work is a method and I release appdatacontext after executing the particular method. So I am not keeping track of the data context anywhere..
public LinqObject GetObject(){
using (appdatacontext = new DataContext()){
---code to select and return object
}
}
I will modify data using the form in UI and submit back my data to DB.
Two approaches are:-
1. Detach and reattach to a different data context using [Detach..Serialise and Attach]
*I have to do a lot of plumping code to enable this functionality*
2. Get the DB object using primary key and make changes in the selected object and SubmitChanges.
Which one is a better approach for doing this task?
I am completely against moving the unit of work to Data Access Layer wise or Web Application Life cycle (httpcontext), because I dont want to track the changes and complicate the entire application structure with unwanted plumping code . I am just using LINQ for making my retrieval and updates to DB easy.
I have never seen anyone discuss these two approaches in LINQ context, that is why I am asking for best practice.
If you don't want to go with (2) because of performance: another option is to attach a new object to submit the updates.
Foo foo=new Foo { FooId=fooId }; // create obj and set keys
context.Foos.Attach(foo);
foo.Name="test";
context.SubmitChanges();
See my answer here.
As per #Chris's comments. I have finally arrived at the solution like:-
function void SaveRow(Table.RowObject object) {
var original=null;
using (context= new DataContext())
{
context.ObjectTrackingEnabled = false;
original = {query}.Single();
}
using(context=new DataContext()){
try
{
context.Table.Attach(object, original);
context.SubmitChanges();
}
catch (Exception exception) {
saveStatus = false;
}
}
}
I kept the update checks to ensure there is concurrency checking, if I disable that I can reduce the amount of where statement generated by Linq.

Entity context lifetime with MySQL

I am new to the Entity Framework 4. I've done a bit of playing around with SQL Server, and MySQL. I ran into a problem using MySQL in regards to lazy loading, and I believe is that the MySQL connector doesn't allow multiple queries on the same connection - it must be closed first.
I would like to run a query, store a reference to the results in a field of my class, and then later on, modify/save it or load related data. However, the context has gone out of scope and been disposed of.
class MyClass {
List<AThing> _stuff;
private void ReadStuff() {
using (var context = new MyEntities()) {
_stuff = context.TableOfStuff.ToList();
}
}
// Stuff is used by other methods, bound to controls, etc.
}
So, does Stuff exist without a context? From what I understand, the context is what does change tracking and the like... Once ToList() is called, my context is useless for another query.
Must I avoid this? Is there a better way of accomplishing this? Am I wrong above?
Your code is fine. When context goes out of scope the items in the list are no longer attached. If you change them you can Attach them to a new context. But there are other ways depening on what you want to do and how you want to do it.
Calling ToList materializes your query but won't leave an open DataReader. So you should be able to execute multiple queries.

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.

Entity Framework Multiple Object Contexts

This question has been asked 500 different times in 50 different ways...but here it is again, since I can't seem to find the answer I'm looking for:
I am using EF4 with POCO proxies.
A.
I have a graph of objects I fetched from one instance of an ObjectContext. That ObjectContext is disposed.
B.
I have an object I fetched from another instance of an ObjectContext. That ObjectContext has also been disposed.
I want to set a related property on a bunch of things from A using the entity in B....something like
foreach(var itemFromA in collectionFromA)
{
itemFromA.RelatedProperty = itemFromB;
}
When I do that, I get the exception:
System.InvalidOperationException occurred
Message=The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects.
Source=System.Data.Entity
StackTrace:
at System.Data.Objects.DataClasses.RelatedEnd.Add(IEntityWrapper wrappedTarget, Boolean applyConstraints, Boolean addRelationshipAsUnchanged, Boolean relationshipAlreadyExists, Boolean allowModifyingOtherEndOfRelationship, Boolean forceForeignKeyChanges)
at System.Data.Objects.DataClasses.RelatedEnd.Add(IEntityWrapper wrappedEntity, Boolean applyConstraints)
at System.Data.Objects.DataClasses.EntityReference`1.set_ReferenceValue(IEntityWrapper value)
at System.Data.Objects.DataClasses.EntityReference`1.set_Value(TEntity value)
at
I guess I need to detach these entities from the ObjectContexts when they dispose in order for the above to work... The problem is, detaching all entities from my ObjectContext when it disposes seems to destroy the graph. If I do something like:
objectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified | EntityState.Unchanged)
.Select(i => i.Entity).OfType<IEntityWithChangeTracker>().ToList()
.ForEach(i => objectContext.Detach(i));
All the relations in the graph seem to get unset.
How can I go about solving this problem?
#Danny Varod is right. You should use one ObjectContext for the whole workflow. Moreover because your workflow seems as one logical feature containing multiple windows it should probably also use single presenter. Then you would follow recommended approach: single context per presenter. You can call SaveChanges multiple times so it should not break your logic.
The source of this issue is well known problem with deficiency of dynamic proxies generated on top of POCO entities combined with Fixup methods generated by POCO T4 template. These proxies still hold reference to the context when you dispose it. Because of that they think that they are still attached to the context and they can't be attached to another context. The only way how to force them to release the reference to the context is manual detaching. In the same time once you detach an entity from the context it is removed from related attached entities because you can't have mix of attached and detached entities in the same graph.
The issue actually not occures in the code you call:
itemFromA.RelatedProperty = itemFromB;
but in the reverse operation triggered by Fixup method:
itemFromB.RelatedAs.Add(itemFromA);
I think the ways to solve this are:
Don't do this and use single context for whole unit of work - that is the supposed usage.
Remove reverse navigation property so that Fixup method doesn't trigger that code.
Don't use POCO T4 template with Fixup methods or modify T4 template to not generate them.
Turn off lazy loading and proxy creation for these operations. That will remove dynamic proxies from your POCOs and because of that they will be independent on the context.
To turn off proxy creation and lazy loading use:
var context = new MyContext();
context.ContextOptions.ProxyCreationEnabled = false;
You can actually try to write custom method to detach the whole object graph but as you said it was asked 500 times and I haven't seen working solution yet - except the serialization and deserialization to the new object graph.
I think you have a few different options here, 2 of them are:
Leave context alive until you are done with the process, use only 1 context, not 2.
a. Before disposing of context #1, creating a deep clone of graph, using BinaryStreamer or a tool such as ValueInjecter or AutoMapper.
b. Merge changes from context #2 into cloned graph.
c. Upon saving, merge changes from cloned graph into graph created by new ObjectContext.
For future reference, this MSDN blogs link can help decide you decide what to do when:
http://blogs.msdn.com/b/dsimmons/archive/2008/02/17/context-lifetimes-dispose-or-reuse.aspx
I don't think you need to detach to solve the problem.
We do something like this:
public IList<Contact> GetContacts()
{
using(myContext mc = new mc())
{
return mc.Contacts.Where(c => c.City = "New York").ToList();
}
}
public IList<Sale> GetSales()
{
using(myContext mc = new mc())
{
return mc.Sales.Where(c => c.City = "New York").ToList();
}
}
public void SaveContact(Contact contact)
{
using (myContext mc = new myContext())
{
mc.Attach(contact);
contact.State = EntityState.Modified;
mc.SaveChanges();
}
}
public void Link()
{
var contacts = GetContacts();
var sales = GetSales();
foreach(var c in contacts)
{
c.AddSales(sales.Where(s => s.Seller == c.Name));
SaveContact(c);
}
}
This allows us to pull the data, pass it to another layer, let them do whatever they need to do, and then pass it back and we update or delete it. We do all of this with a separate context (one per method) (one per request).
The important thing to remember is, if you're using IEnumerables, they are deferred execution. Meaning they don't actually pull the information until you do a count or iterate over them. So if you want to use it outside your context you have to do a ToList() so that it gets iterated over and a list is created. Then you can work with that list.
EDIT Updated to be more clear, thanks to #Nick's input.
Ok I get it that your object context has long gone.
But let's look at it this way, Entity Framework implements unit of work concept, in which it tracks the changes you are making in your object graph so it can generate the SQL corresponding to the changes you have made. Without attached to context, there is no way it can tack changes.
If you have no control over context then I don't think there is anything you can do.
Otherwise there are two options,
Keep your object context alive for longer lifespan like session of user logged in etc.
Try to regenerate your proxy classes using self tracking text template that will enable change tracking in disconnected state.
But even in case of self tracking, you might still get little issues.

Categories