Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity framework ObjectContext share - pros and cons

In my project I use entity framework 4.0 as ORM to persist data in a SQL Server.

My project is a ribbon from application with a grid view and navigation tree in the main form with ribbon panel on top of it. My app basically acts a CRUD UI with very little business logic.

Being first time with EF, I developed this project by creating and holding an instance of objectContext in the orchestrating form (main form or the one that shows up as application to user) as a member variable and bound a query to a grid view.

For various events like ribbon panel button clicks, grid view row clicks etc, I open another windows form. In that window form I create another object context and stored in member variable of that form class.

I had read through few blogs and questions like:

  1. How to decide on a lifetime for your objectcontext
  2. Entity Framework and ObjectContext n-tier architecture etc.

One set of authors suggests to share the object context while other suggest to short lived and non-shared.

I reached this state of confusion because I am now in a state where the changes I made to objectContext in one of the child form is not reflecting the parent form that showed it. I attempted to refresh but still nothing useful. Just for an experiment, I shared the objectContext that I first created in the most parent class through constructor injection and my problem of change reflection is solved.

It is a huge work for me to convert all my child forms to share objectContext. But I am ready if it is worth. I am not sure what will be the lurking problems of sharing it?

I may opt for a static instance of objectContext as I am not using this for Web and not planning for multi threaded scenarios. If required I can rise to as a singleton.

My Questions:

  1. To share or not to share ObjectContext for my situation?
  2. If not to share, how can I solve my present problem of updating one objectContext with the changes made in other?
  3. If to share - which would be better way? Static or singleton or something else?

The details of the project and environment are as below:

  • Winforms
  • C#
  • VS 2012
  • EF 4.0, model created with data first approach.

I am posting this after searching and reading through many questions and blog posts. The more I read, the more confusing it becomes :) Please bear with me if I am leaving someone to assume something to answer. I will try to update the question if such clarifications are asked through comments.

like image 678
Narayanan Avatar asked Mar 07 '13 06:03

Narayanan


1 Answers

Your Questions

To share or not to share ObjectContext for my situation? Do not share your context. The EntityFramework context should follow a UnitOfWork pattern. Your object context should be as short lived as possible without unnecessarily creating/destroying too many contexts. This usually translates to individual "operations" in your app as units of work. For a web app/api this might be per HttpWebRequest, or you might do it per logical data operation (for each of your implemented pieces of "Business Logic").

For example:

  • LoadBusinssObjects() would create a context, load your list of data plus any related data you want then dispose of the context.
  • CreateBusinessObject() would create a context, create an instance of some entity, populate it with data, attached it to a collect in the context, save changes and then dispose of the context.
  • UpdateBusinessObject() would read some object from the context, update it, save changes, and dispose of the context.
  • DeleteBusinessObject() would find a business object in the context, remove it from the collection in the context, save changes and dispose of the context.

If not to share, how can I solve my present problem of updating one objectContext with the changes made in other? This is a job for a pub/sub architecture. This can be as simple as a few static event handlers on your objects for each operation you implemented above. Then in your code for each business operation, you fire the corresponding events.

If to share - which would be better way? Static or singleton or something else? This is incorrect. The EF context will continue to grow in memory footprint as the context's state manager continuously collects up cached objects (both attached and not-attached) for every single interaction you do in your application. The context is not designed to work like this.

In addition to resource usage, the EF context is not thread safe. For example what if you wanted to allow one of your editor forms to save some changes at the same time as the tree list is loading some new data? With one static instance you better make sure this is all running on the UI thread or synchronized with a semaphore (yuck, and yuck - bad practices).

Example

Here's an example using C# and code first approach as per your post. Note, I'm not addressing things like data concurrency or threading to keep the example short. Also in a real application this concept is implemented with generics and reflection so that ALL of our models have basic events on them for Creating, Updating, Deleting.

public class MyCodeFirstEntityChangedArgs : EventArgs
{
    /// <summary>
    /// The primary key of the entity being changed.
    /// </summary>
    public int Id {get;set;}

    /// <summary>
    /// You probably want to make this an ENUM for Added/Modified/Removed
    /// </summary>
    public string ChangeReason {get;set;}
}

public class MyCodeFirstEntity
{
    public int Id {get;set;}
    public string SomeProperty {get;set;}

    /// <summary>
    /// Occurs when an instance of this entity model has been changed.
    /// </summary>
    public static event EventHandler<MyCodeFirstEntityChangedArgs> EntityChanged;
}

public class MyBusinessLogic
{
    public static void UpdateMyCodeFirstEntity(int entityId, MyCodeFirstEntity newEntityData)
    {
            using(var context = new MyEFContext())
            {
                // Find the existing record in the database
                var existingRecord = context.MyCodeFirstEntityDbSet.Find(entityId);

                // Copy over some changes (in real life we have a 
                // generic reflection based object copying method)
                existingRecord.Name = newEntityData.Name;

                // Save our changes via EF
                context.SaveChanges();

                // Fire our event handler so that other UI components 
                // subscribed to this event know to refresh/update their views.
                // ----
                // NOTE: If SaveChanges() threw an exception, you won't get here.
                MyCodeFirstEntity.EntityChanged(null, new MyCodeFirstEntityChangedArgs()
                {
                    Id = existingRecord.Id,
                    ChangeReason = "Updated"
                });
            }
    }
}

Now you can attach event handlers to your model from anywhere (its a static eventhandler) like this:

MyCodeFirstEntity.EntityChanged += new EventHandler<MyCodeFirstEntityChangedArgs>(MyCodeFirstEntity_LocalEventHandler);

and then have a handler in each view that will refresh local UI views whenever this event is fired:

static void MyCodeFirstEntity_LocalEventHandler(object sender, MyCodeFirstEntityChangedArgs e)
{
    // Something somewhere changed a record! I better refresh some local UI view.
}

Now every UI component you have can subscribe to what events are important to it. If you have a Tree list and then some editor form, the tree list will subscribe for any changes to add/update/remove a node (or the easy way - just refresh the whole tree list).

Updates Between Applications

If you want to go a step further and even link separate instances of your app in a connected environment you can implement a pub/sub eventing system over the network using something like WebSync - a comet implementation for the Microsoft Technology Stack. WebSync has all the stuff built in to separate events into logical "channels" for each entity/event you want to subscribe to or publish to. And yes, I work for the software company who makes WebSync - they're paying for my time as I write this. :-)

But if you didn't want to pay for a commercial implementation, you could write your own TCP socket client/server that distributes notifications for the above events when an entity changes. Then when the subscribing app gets the notification over the network, it can fire its local event handlers the same way which will cause local views to refresh. You can't do this with a poorly architected static instance of your data context (you'd be bound to only ever have one instance of your app running). With some good setup early on, you can easily tack on a distributed pub-sub system later that works across multiple instances of native apps and web apps all at the same time! That gets very powerful.

like image 182
BenSwayne Avatar answered Oct 15 '22 14:10

BenSwayne