views:

220

answers:

2

Good day,

I am in the middle of development of a WPF application that is using Entity Framework (.NET 3.5). It accesses the entities in several places throughout. I am worried about consistency throughout the application in regard to the entities. Should I be instancing separate contexts in my different views, or should I (and is a a good way to do this) instance a single context that can be accessed globally?

For instance, my entity model has three sections, Shipments (with child packages and further child contents), Companies/Contacts (with child addresses and telephones), and disk specs. The Shipments and EditShipment views access the DiskSpecs, and the OptionsView manages the DiskSpecs (Create, Edit, Delete). If I edit a DiskSpec, I have to have something in the ShipmentsView to retrieve the latest specs if I have separate contexts right?

If it is safe to have one overall context from which the rest of the app retrieves it's objects, then I imagine that is the way to go. If so, where would that instance be put? I am using VB.NET, but I can translate from C# pretty good. Any help would be appreciated.

I just don't want one of those applications where the user has to hit reload a dozen times in different parts of the app to get the new data.

Update:

OK so I have changed my app as follows:

  1. All contexts are created in Using Blocks to dispose of them after they are no longer needed.
  2. When loaded, all entities are detatched from context before it is disposed.
  3. A new property in the MainViewModel (ContextUpdated) raises an event that all of the other ViewModels subscribe to which runs that ViewModels RefreshEntities method.
  4. After implementing this, I started getting errors saying that an entity can only be referenced by one ChangeTracker at a time. Since I could not figure out which context was still referencing the entity (shouldn't be any context right?) I cast the object as IEntityWithChangeTracker, and set SetChangeTracker to nothing (Null).

This has let to the current problem: When I Null the changeTracker on the Entity, and then attach it to a context, it loses it's changed state and does not get updated to the database. However if I do not null the change tracker, I can't attach. I have my own change tracking code, so that is not a problem.

My new question is, how are you supposed to do this. A good example Entity query and entity save code snipped would go a long way, cause I am beating my head in trying to get what I once thought was a simple transaction to work. Any help would elevate you to near god-hood.

+2  A: 

Good question, Cory. Thumb up from me.

Entity Framework gives you a free choice - you can either instanciate multiple contexts or have just one, static. It will work well in both cases and yes, both solutions are safe. The only valuable advice I can give you is: experiment with both, measure performance, delays etc and choose best one for you. It's fun, believe me :)

If this is going to be a really massive application with tons of concurrent connections I would advise using one static context or one static, core context and just few additional ones just to support the main one. But, as I wrote just few lines above - it's up to your requirements which solution is better for you.

I especially liked this part of your question:

I just don't want one of those applications where the user has to hit reload a dozen times in different parts of the app to get the new data.

WPF is a really, really powerful tool and basically times when users have to press buttons to refresh data are gone forever. WPF gives you a really wide range of asynchronous, multithreading tools such as Dispatcher class or Background worker to gently refresh desired data in the background. This is really great, because not only you don't have to worry about pressing various buttons, but also background threads don't block UI, so data is refreshed transparently from user's point of view.

WPF together with Entity Framework are really worth the effort of learning - please feel free to ask if you have any further concerns.

Piotr Justyna
Piotr, please see conversation with Hightechrider. I am essentially teaching myself WPF and EF as I go along. My first apps were pretty ugly and kludgy, but they are getting more refined as I go. Any good resources you have for managing ViewModel functionality would be terrific. I see a plethora of results when searching, but most are pretty general explanations of MVVM and the like.
OffApps Cory
Hi, imo the best MVVM article for beginners is this one: http://www.codeproject.com/KB/WPF/TreeViewWithViewModel.aspx This is as simple as possible providing you with as much information as you need to start by yourself. Please report your progress :)
Piotr Justyna
+3  A: 

A global static context is rarely the right answer. Consider what happens if the database is reset during the execution of this application - your SQL connection is gone and all subsequent requests using the static context will fail.

Recommend you find a way to have a much shorter lifetime for your entity context - open it, do some work, dispose of it, ...

As far as putting your different objects in the same EDMX, that's almost certainly the right answer if they have any relationships between objects you'll want them in the same EDMX.

As for reloading - the user should never have to do this. Behind the scenes you can open a new context, reloading the current version of the object from the database, applying the changes they made in the UI annd then saving it back.

You might want to look at detached entities also, and beware of optimistic concurrency exceptions when you try to save changes and someone else has changed the same object in the database.

Hightechrider
OK so if I am using multiple contexts, how will one context know to refresh data it has pulled. Would I have it monitor a propertychanged event set by the other context?
OffApps Cory
The context should be closed and gone away when the application is in the idle state. All you have is either DTOs or detatched entities in this state. When someone clicks on something you open a single context, reattach your entities or reload them and apply the changes from the UI, and then call savechanges handling any optimistic concurrency exceptions it might throw, and then update your views and finally dispose of the context. Think of the context as bounding a single unit of work.
Hightechrider
That represents a fundamental change in how I view EFs functionality. I was under the impression that the context was expected to hold references to the objects it creates from data until the viewmodel disposes of it (when the view is disposed of).Currently I have my ViewModels loading Shipment objects via EF, which are loaded into a custom collection and displayed in the View. After changes are made to the in memory objects, I call save changes and the same context (right?) makes the updates to the server. If that is not correct, when I save changes, does it work differently?
OffApps Cory
Take a look at these ... http://stackoverflow.com/questions/1169188/… http://stackoverflow.com/questions/1251917/… http://stackoverflow.com/questions/1949037/… If your view is around for a short enough time you can use the same context to create it and track changes made to the data by the user and save it back, sure. But if you want to be sure that your user can go to lunch, come back and resume work whilst the IT department has restarted SQL in the meantime, then it isn't. But in no case is it a good idea to have a single static global scope for the object context.
Hightechrider
Ahh! I see how I can easily attach entities to a new context after having disposed of the original one. As far as alerting other ViewModels that their data needs to be updated, how would you accomplish that? I guess more to the point, how can I get the ViewModel to "subscribe" to an event from another ViewModel? I am using the Ocean Framework that Karl Shifflett wrote which has some very useful features including an OnPropertyChanged method that simplifies UI notification of property change, but I am clueless as to how to adapt that to notifying non-UI elements of change. Any thoughts?
OffApps Cory
Been poking around and found that I can easily access the MainWindow ViewModel via App.Current.MainWindow.DataContext. Now there I can add a property (lets call it DataUpdated; a boolean) that other ViewModels can listen to via a custom event. AddHandler App.Current.MainWindow.DataContext.Update, AddressOf(RefreshEntities). I don't have time to implement all this tonight, so I will have to wait 'til tomorrow. Am I on the right track?
OffApps Cory