Sorry, if this is a duplicate. Please point me to the appropriate question if this is but I could not find exactly what I am looking for.
So I am using a Linq to SQL datacontext for entity tracking and persistence in an ASP.NET web application. It is for an Intranet application that does not have a ton of users at a time. Right now I cam storing the datacontext in session state, which makes me feel dirty! It seems like I need the context always to be present though because I need to preserve the change tracking on the entities that are being modified. All of our screens have a Save button that would then call SubmitChanges() on the DataContext and persist all of the pending changes in memory.
Should I be storing the DataContext? Should I be disposing of it at the end of each request and then recreate it somehow and get the pending changes? If I should recreate it every time, I dont understand how the context could know what has changed without a ton of redundant database hits on each request.
First, I would say to stop putting things in Session altogether. Especially if you don't have a lot of users, just load the data when you need it.
Don't store the data context at all. Just create a new one on each page when you need it. When they hit the Save button, recreate a data context, load the object from the database, make the changes necessary based on the form input, and then save it back to the database. It should just be two database hits for each object, one to load, and then one to save it back.
I think the best practice with the data context is the Unit of Work pattern, where the scope of the Unit of Work is the single request that you are servicing. Instantiate a new data context each time you need to make changes. If you're concerned about overwriting changes that have been made after drawing the previous page, then consider using and persisting a version/timestamp in a hidden field and checking it against that returned from the data context when retrieving the entity to update.
Related
Is it possible to keep on to the 'changes' you will be wanting to make with Entity Framework?
For instance I do an update query then the connection fails, I close the app and then tomorrow I want it to do that update query when a connection is restored.
Is a thing like that possible with Entity Framework 6?
You could possibly create your own ChangeTracker, like in this tutorial, which saves all changes to a file. Parsing the file for a later use might be tricky.
The other option would be to use retry logic and hope the connection problem was just a slight hiccup
I think ZorgoZ is right and this answer will not address your actual question, but what I think it is your actual problem (see XY problem): you fail to save some changes (business-wise) and you want to be able to retry saving them later, not necessary some EF changes that you want to persist a later moment.
One way to do it is to store the business information that trigger the change and retry the whole flow:
define some sort of queue stored in a file, isolated storage etc. (depends on your technology)
your update flow should persist some sort of record / object in the queue that contains all relevant information + a status (e.g. Queued, Save error etc.)
update is tried. If it fails, you can have a status update (e.g. Save error)
the user closes the application
later, the user opens the application seeing the queue items status (item 1 saved OK, item 2 save error etc.)
Besides EF technical issues, this implementation allows for flow changes that include things outside EF save changes (e.g. also check some external API) and abstracts away the data access layer entirely (EF changes serialisation implementation has a big chance to depend on some EF specifics).
Also I sense context information serialization (e.g. data behind some form) is easier to implement than EF context changes serialization.
The way I use LINQ SQL is with 1 global datacontext.
I am having problems though. I have one page I go to that grabs all Cases in the db and copies data from the result IEnumerable.
Then, when I navigate to go do some updates on those cases, it fails.
Is there anything I can do to fix concurrency issues or these types of general issues while still only using 1 data context per user session? Would it help maybe I used a new data context every page load or something?
Thanks
You cannot have 1 global datacontext in ASP.NET; you need one global context per HTTP request, because you'll deal with issues like you mentioned. LINQ to SQL tracks objects changes in a graph, and a static context will contain instances of objects disposed in a previous HTTP request. Plus, overtime, it would get bloated and take up a lot of memory. The approach is to store an instance of it in HttpContext.Current.Items.
I am using a single global DataContext object for my entire application. The application should work in a network environment where multiple instances of it work simultaneously with a shared SQL database.
The database changes in one application are not reflected in other instances until I call DataContext.Refresh method. Problem is this function is time consuming and I cannot change my code back to using different datacontext objects for different operations.
What should I do to always keep the datacontext object in each application updated?
RefreshMode Enum is the correct bit. Just a matter of deciding when to use it, and using the DataContext correctly. Think of the DataContext as a unit-of-work, and flag the refresh mode when your prepairing a submit (like KeepChanges or something). In that way, the users info is pushed (or bubbles up on conflict) and it's automagically updated with the freshest stuff in the database.
I think everyone else has rightly pointed out the wrongness of a global datacontext. You'd either have to set a refresh time or give the user a button to refresh if you wanted to update their display more frequently. I don't know of another way there.
let us assume that I have a reusable business layer that further makes use of a data access layer that was implemented using Entity Framework 4.0. The entities returned/consumed by the business layer are self-tracking, allowing us all the goodies that come with those type of entities.
I would like to be able to store the entities I work with across post backs (on order to avoid re-querying every time). Basically let us assume I have a paged GridView with 10 items in it, and something like a DetailsView to edit those items. Every time you select a new row on the grid, the details view updates with the information of the selected row. My preference would be to only query for the entities on the initial request of the page and store it in session. Then subsequently I have a list of entities that I can work with and eventually modify and send back to the business layer with all of the changes.
I really want to use session instead of view state to reduce the page payload (self tracking entities are heavy) however I really like view state for this because of the fact that when the user navigates away from the page there is no residual effect.
Some of the things that worry me are:
When a user navigates away from the page to another page, the entities from the previous page are still in session. I could always do something on load of a page to do housekeeping type of work. Not sure if that's good practice.
I am worried about people opening browser tabs and having two views into the same page, it seems like that might pose a problem.
Is this even a good approach? Seems like I am trying to have the best of all worlds, it would definitely be much easier to simply re-query on every post back for the entities and pay the 50-100ms hit of the database trip.
Your thoughts are greatly appreciated.
Take the hit of going back to the database. If your site is low trafficked enough to let you consider sticking this into the session, you'll be fine for the query hit.
There are also advantages to this, in that you could have simpler concurrency checking and you'll also not run into the problems you alude to above, of session 'cross-over' when somebody opens two tabs.
If you are going to the database then you are pretty much loosing the benefits of Self Tracking entity which has the ability to track changes when objectcontext is not around. Thus asp.net stateless scenario is a good option for STE. I think u only need to only keep one entity in viewstate that is the one that u are editing which should not be that heavy. You have the option of Session but i never liked session for the same reason you mentioned. It causes so many bugs down the road when something is left hanging.
This seems like it would be a common issue to be but I don't know the best way to solve it. I want to be able to send an Entity to a view, have changes be made to the entity in the view, but then cancel (remove) those changes if the user cancels out of the view. What is the proper way to do this.
Here are two options I have but I think there should be others that are better
1) Take an entity, create a clone, send the clone to the view...if changes are accepted, update the original entity with the clone's values
2) Send the entity to the view, if the user cancels, remove the entity from NHibernate's cache and reload it from the database
For (2), the issue for me would be that the old entity could still be referenced throughout my project after it has been removed from the cache.
Edit:
Ok, so the evict method is the way to go if I am implementing method (2). Thanks, I could not remember the details of that one. However, the issue of view objects referencing my old evicted entities makes the issue tough to deal with. I can't just have my view automatically update to a new entity without having custom code in each one to rebind when my custom eviction event is raised. And rebinding may not be trivial in certain cases. I need to think on this some more as I may be over complicating but at the moment, this method seems trickier.
I suspect I am going to be stuck with method (1) which has its own set of problems but will wait a bit longer to see if anyone else has some ideas.
Edit 2: Just found this. I think it pretty much covers the answer in detail and comes with a great demo project - Building a Desktop To-Do Application with NHibernate - http://msdn.microsoft.com/en-us/magazine/ee819139.aspx
In addition to this, NHibernate has a Session.Refresh(Object entity) function which seems to solve the exact problem. So, when an entity is changed but then cancelled before save, I can just call Session.Refresh to reload it from the database and discard the changes.
I'll go for option 1 and use what is called a ViewModel instead of your entity.
The ViewModel is representation of you model for a specific view. In the ViewModel you can mix data from different entities and pre-format values to fit the view. Is an elegant way of passing data to a view and you can accomplish what you want easily.
Using ViewModels is becoming the preferred way of working in ASP.net MVC and Silverlight / WPF.
To read more about Viewmodels: http://blogs.msdn.com/dphill/archive/2009/01/31/the-viewmodel-pattern.aspx
The best way to do this is to call the Evict method on the ISession used to load the object. This will remove the object from the session cache. and you can then reload and redisplay it.
Evicting the object from the session makes it transient detached so if there are still references to it in the project they will not be persisted when the session is flushed. How you deal with that depends on your application but I would suggest raising an event to notify subscribers that they need to re-load the object.