Improve company productivity with a Business Account.Sign Up


Entity Framework 4 POCO update with disconnected objects

Posted on 2011-03-14
Medium Priority
Last Modified: 2012-08-13
Hi experts,
I have something still not clear about updates in EF 4 with POCO classes (disconnected object).

I have let's say an objet called user and a graph like this:

user.FirstName (property)
user.Orders (collection of orders)
user.Profile (object profile)
user.Friends (collection of friends)
and so on

I can add or delete, but my problem starts when I need to update.
What I usually do is to retieve the original entity from the context (with the navigation properties) and then I iterate through the object graph in order to manually update the properties for all the navigation properties as well.
Sometime happens that the object contains some object to add and not to update.
For istance the user can contains a new order, and so I need to add the new order and not update (But for the user itself it's an update).
Does exist a flexible way to have a generic function where I can pass the user or even better a generic entity (that can contains elements to update and/or elements to add) and EF understands what to add or what to update?

something like

 public ResultObject UpdateUser(User user)
       //context analyzes the object user with navigation properties (collection as well)
       //and add or updates everything automatically

If doesn't exist a way for that can someone explain me the concept for updating disconnected object with navigation properties to update or add?

P.S. I can't use self tracking entities

Thanks in advance
Question by:xtremereality
  • 3
  • 2
  • 2
LVL 21

Expert Comment

by:Craig Wagner
ID: 35137912
I'm not sure what you mean by a generic function. Your method should simply retrieve the User and related child objects (using .Include) so the whole (existing) object graph is in memory. Loop over the incoming object graph and if the object is already in the collection you retrieved from the database you transfer the property values over and if not you create a new object and add it to the collection. Part of the power of EF is that it will figure out which objects are new and which are existing to be updated.
LVL 21

Expert Comment

by:Craig Wagner
ID: 35138001
Pseudo code would look something like the following, but I'd probably break it into multiple smaller methods for readability and maintainability (e.g. one method to handle the Orders, one method to handle the Profile, etc).
public ResultObject UpdateUser(User user)
    User existingUser = dbContext.Users
                            .Where( u => u.UserId == user.UserId )
    if( existingUser != null )
        existingUser.FirstName = user.FirstName;
        // etc for rest of user properties
        if( existingUser.Profile == null )
            // user doesn't have a profile, create a new one
            // and add it to graph
            Profile existingUser.Profile = new Profile();

        existingUser.Profile.Prop1 = user.Profile.Prop1;
        // etc for rest of user properties

        foreach( Order order in user.Orders )
            existingOrder = Orders
               .Where( o => o.OrderId == order.OrderId ).SingleOrDefault();
            if( existingOrder == null )
                existingOrder = new Order();
                existingUser.Orders.Add( existingOrder );

            existingOrder.prop1 = order.Prop1;
            // copy rest of order properties

            // Do a loop similar to the above for Friends and
            // any other collections.
        // everything is new, add object graph to context


Open in new window


Author Comment

ID: 35138028
Thanks for the answer Craig.
What I mean is this: It's not clear to me how to perform an update in EF4 with poco in a disconnected scenario.
Let me give you an example:

On the client:

var user = repository.GetUser(userId);

this user contains navigation properties (and some of them are collections).

var friend = user.Friends.FirstOrDefault();

friend.Something = foo;
user.Name = "new name";

var contact = new contact { something = foo };

user.Address.Street = "new street";

var result = repository.UpdateUser(user);

On the data access layer

function bool UpdateUser(User user)
      // How to perform updates of the user object?
      // it contains new elements as well as modified elements.
      // and it's disconnected

Hope is more clear what I mean and where I need some help to try to understand.

If I have to iterate through the object collection how can I know if an element of the collection is new or updated?

The 14th Annual Expert Award Winners

The results are in! Meet the top members of our 2017 Expert Awards. Congratulations to all who qualified!


Author Comment

ID: 35138109
Sorry Craig I didn't see your coding 'cos I was writing my reply.
What you wrote is what I usually do (as I wrote on my original post).
But my real object has tons of properties and collections and I was wondering if there is a better and more simple way to perform the update. In this case I have to perform lots of queries to compare the old object with my new object in order to do the appropriate changes.
I saw on some website (and here is where my confusion starts) there are other methods to perform update, with detectChanges, attach object to the context...
But I didn't find an example that fits my needs.
LVL 21

Accepted Solution

Craig Wagner earned 2000 total points
ID: 35138784
We use POCOs with Entity Framework as well, so we've run into these issues ourselves.

The problem with the Attach or AttachTo methods is that they object is attached to the context in an Unchanged state. We never did find a way to change the state of the object (and its properties) without going through each property and assigning it a value.

DetectChanges is automatically called when calling SaveChanges. It is just making sure that the POCO and the ObjectStateEntry held in the ObjectContext are in sync so EF knows what statements to generate.

What we ended up doing was writing a reflection-based method to copy the properties from one instance of an object to another. We have a common base class for all our POCOs (called BusinessContract). The method has to make sure it doesn't copy child object references or collection references. This would save you the tedious thisObject.Property1 = thatObject.Property1 code but you would still need to do the looping and creation of new objects if they aren't already in the collection. You could try adapting it to handle those conditions as well, but we tried for a couple of days and finally gave up because of the number of problems it was creating for us. Every time we thought we'd solved one problem it would cause another.

Realistically though, this is code you should only have to write once. It'll be tedious, but once it's written you're done with it.

public void OverwriteWith(object source, bool overwriteWithNulls = true)
    // If source is null, we are out of here
    if (source == null)
        throw new ArgumentNullException("source");

    //get an array of all the properties on the business contract
    PropertyInfo[] sourceProperties = source.GetType().GetProperties();

    Type targetType = this.GetType();

    foreach (PropertyInfo sourceProperty in sourceProperties)
        //get the value to copy
        object sourcePropertyValue = sourceProperty.GetValue(source, null);

        //if the value is null only perform copy if overwriteWithNulss is set to true
        if (overwriteWithNulls || (sourcePropertyValue != null))
            //get the Base Type of the property. As long as it isn't a child business contract
            //we want to copy the value. 
            Type propertyType = sourceProperty.PropertyType;
            Type baseType = propertyType.BaseType;
            if (baseType != typeof(BusinessContract) &&
                (!propertyType.IsGenericType || propertyType.GetGenericTypeDefinition() != typeof(ICollection<>)))
                PropertyInfo targetProperty = targetType.GetProperty(sourceProperty.Name);

                // Make sure the property name and type are identical on the source and target
                if (targetProperty != null &&
                    targetProperty.PropertyType == sourceProperty.PropertyType &&
                    targetProperty.SetValue(this, sourcePropertyValue, null);

Open in new window

LVL 17

Expert Comment

by:Jesse Houwing
ID: 35140408
Have you simply tried adding your existing Poco object to an empty collection in the datacontext

The second example on this page suggests it should work:

// Disable proxy object creation.
context.ContextOptions.ProxyCreationEnabled = false;


And then calling context.DetectChanges()
And then calling context.SaveChanges()

That should do the trick if I read the docs right...
LVL 17

Expert Comment

by:Jesse Houwing
ID: 35140444
Further reading contradicts my previous statement, but there are some helper methods. Read the following whole post for tips:

Featured Post

Get your problem seen by more experts

Be seen. Boost your question’s priority for more expert views and faster solutions

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Real-time is more about the business, not the technology. In day-to-day life, to make real-time decisions like buying or investing, business needs the latest information(e.g. Gold Rate/Stock Rate). Unlike traditional days, you need not wait for a fe…
This article aims to explain the working of CircularLogArchiver. This tool was designed to solve the buildup of log file in cases where systems do not support circular logging or where circular logging is not enabled
SQL Database Recovery Software repairs the MDF & NDF Files, corrupted due to hardware related issues or software related errors. Provides preview of recovered database objects and allows saving in either MSSQL, CSV, HTML or XLS format. Ensures recov…
Stellar Phoenix SQL Database Repair software easily fixes the suspect mode issue of SQL Server database. It is a simple process to bring the database from suspect mode to normal mode. Check out the video and fix the SQL database suspect mode problem.

606 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question