0

I'm having an issue where Entity Framework isn't persisting changes to the DB. I use a static method to load up some values and the Entity context is thrown away (in a using statement).

The objects are then loaded into a WPF DataGrid where they can be manipulated by the end user.

When the user is finished making changes an "update" button is pressed and the list of objects is sent back to the data layer to be persisted to the DB. I can see objects that were changed in the UI reflect their new value (ie not a data binding issue).

I would assume since the entity context that loaded the objects has since been disposed of I should then attach these objects to be persisted to the newly created context. Correct? When I do this the entity state of the modified object (I can see that is what the state is set to) changes to "Unchanged". Nothing is persisted to the DB.

What the heck am I missing?!

Here is the code to load and update the values:

public static List<SSIS_Configuration> GetConfigurationValuesForTenant(string tenantKey, SqlConnectionString connectionString)
    {
        List<SSIS_Configuration> configStrings = new List<SSIS_Configuration>();
        if (connectionString.IsValid())
        {
            try
            {

                using (SSISFrameworkEntities entities = new SSISFrameworkEntities(connectionString.ToEDMXString("SSISFramework.SSISFramework")))
                {
                    string configFilterStartingValue = "CommonConfig_" + tenantKey;

                    configStrings = (from configString in entities.SSIS_Configurations
                                    where configString.ConfigurationFilter.StartsWith(configFilterStartingValue)
                                    select configString).ToList();
                }
            }
            catch { }
        }

        return configStrings;
    }

    public static void UpdateConfigurations(List<SSIS_Configuration> configurations, SqlConnectionString connectionString)
    {
        if (connectionString.IsValid())
        {
            try
            {
                using (SSISFrameworkEntities entities = new SSISFrameworkEntities(connectionString.ToEDMXString("SSISFramework.SSISFramework")))
                {
                    foreach (SSIS_Configuration config in configurations)
                    {
                        entities.Attach(config);
                    }

                    entities.SaveChanges();
                }
            }
            catch { }
        }
    }
Mike G
  • 1,956
  • 1
  • 30
  • 62
  • 1
    Try keeping the context in a place like App.Current.Properties["context"]. Unless they are self tracking entities, the changes won't be noticed when using a new context even if you attach. – Dustin Davis Aug 29 '11 at 18:24
  • 1
    My preference is to hold my context inside an IoC container such as Unity. Then I can set parameters to control the lifecycle. You can then use contructor injection to make sure all your viewmodels have access to the context object. – Winger Aug 29 '11 at 18:29
  • @Dustin, I don't know if that will be appropriate for my solution as this code is stored in a class library to be used by different end UI solutions. While the main use will be with a Windows WPF client it will most likely be used by a console app and perhaps a Silverlight app. When is App.Current available? – Mike G Aug 29 '11 at 18:29
  • @Mike G the point is, when you destroy the context you lose tracking. Use self tracking entities or don't destroy the context. – Dustin Davis Aug 29 '11 at 18:35
  • @Winger, my thought was to build a static "Runtime" class, but I don't have a need for it other than this holder. I've typically built these static classes before, but wanted to keep the number of utility classes down in this solution. If I can't get any other good solutions I may have to revert to that design. I had thought I could treat the entity context as I did with "requests" in a web app. I would build a new context for each request and then dispose of it at the end of the request. I thought this would do the same. – Mike G Aug 29 '11 at 18:36
  • @Dustin, I thought that was the whole point of the object state manager. That it tracked the changes and then when you "attached" the entity back to a context it would reconcile all the changes. I've tried to attach and then "refresh" with the client wins set. Still didn't work. – Mike G Aug 29 '11 at 18:38
  • @Mike G, your static class to hold the context reference should do the trick – Winger Aug 29 '11 at 18:54
  • @Winger, I was going to do that, but first was looking at the tracking changes stuff. Now I've destroyed my Entity model. My "tables" on the entity context no longer have "ToList" on them. Everything is very odd now. Shouldn't have done that! Should have also had this in source control by now! – Mike G Aug 29 '11 at 19:06
  • How many tables do you have @Mike G? If it's not many (a dozen or so) you could generate your entity model from the database easy enough. If you use the entity context and keep it around to track changes it should solve the problem you are having. – Winger Aug 29 '11 at 19:09
  • @Winger, I regenerated my entity context. I'm dealing with a little more than a half dozen tables. I guess I'm going to have to build a thread safe class. I didn't want to do this. I thought I could treat each entity context created as if it were similar to having the contexts live on different HTTP requests (this is where I've done attaching and detaching in the past). However, I guess I must have lost my mind as I don't know what to do. I have one more idea I'm going to try before doing thread safe class. – Mike G Aug 29 '11 at 19:31

1 Answers1

1

WPF application is scenario for attached entities so you should not dispose context if you are going to change entities loaded from the context. If you dispose it you must implement a lot of additional logic because you must tell a new context about every single change a user did to the entities and relations.

So in your scenario calling Attach will only connects entities to the context but you need to set also their state (attaching put entities into Unchanged state). Be aware that you must set state correctly to Modified, Deleted or Inserted based on the operation you want to perform. If your changed entities have some relations which have been also changes you must set state for related entities as well and in case of changed relation between entities you must change state of relations itself as well.

Community
  • 1
  • 1
Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • I want to point out that my original question did not include this code but I tried this and it still didn't work. The objects would come back from the view layer and I would set them all as modified, but they still wouldn't update. I figured out that my issue was with the underlying data object instead. It was a view, but I was not getting an error telling me that an update couldn't be performed. In one of my configurations I was able to generate this error and now have figured that I must update the data via stored proc. – Mike G Aug 30 '11 at 12:46