views:

109

answers:

2

I can't seem to update my database from disconnected poco objects. In this example, I fetch an ApplicationUser object, update varchar(100) field SSOID, but no changes take effect. Even when I refetch the object in the save method, nothing gets sent to the db.

If I try to call ApplyCurrentValues, it throws

An object with a key that matches the key of the supplied object could not be found in the ObjectStateManager. Verify that the key values of the supplied object match the key values of the object to which changes must be applied.

 public void Save(ApplicationUser au)
 {
     ApplicationUser original = context.ApplicationUsers.FirstorDefault(a => a.UserID == au.UserID);
     context.ContextOptions.ProxyCreationEnabled = false;  //changing this has no effect

     if(original == null)
     {
         context.AddObject("ApplicationUsers",au); //this works!
     }
     else
     {
          ///let's manually set some properties on the object I just fetched.
          original.SSOID = au.SSOID;
          ObjectStateEntry entry = null;
          context.DetectChanges();
          context.ObjectStateManager.TryGetObjectStateEntry(original.EntityKey, out entry);
          //entry is still null!
          context.ApplicationUsers.ApplyCurrentValues(original);  //BOOM!!
      }
      context.SaveChanges();
      return;
  }

I tried everything I can think of, even making ApplicationUser implement System.Data.Objects.DataClasses.IEntityWithKey, which supposedly isn't necessary.

Here's the mapping:

<EntitySetMapping Name="ApplicationUsers">
    <EntityTypeMapping TypeName="MyCompanyName.ApplicationUser">
         <MappingFragment StoreEntitySet="ApplicationUser">
            <ScalarProperty Name="UserID" ColumnName="UserID" />
            <ScalarProperty Name="SystemID" ColumnName="SystemID" />
            <ScalarProperty Name="Username" ColumnName="Username" />
            <!--snip-->
            <ScalarProperty Name="CreatedOn" ColumnName="CreatedOn" />
            <ScalarProperty Name="CreatedBy" ColumnName="CreatedBy" />
            <ScalarProperty Name="SSOID" ColumnName="SSOID" />
         </MappingFragment>
     </EntityTypeMapping>
</EntitySetMapping>
+2  A: 

Are you using the straight/simple POCO T4 template, or the self-tracking entities template??

The straight POCO have no support for any change tracking whatsoever - if you want that, you need the self-tracking entities.

See resources:

Update: I think you are quite close to the right way of doing things here. You re-load the original state of the object (I would probably add a check on a timestamp or something to make sure the object in store hasn't been changed in the meantime).

Once you've done that, I believe you just need to detect yourself what changes have happened / where differences exist between au and original; update the original accordingly, and then just simply call context.SaveChanges().

As far as I understand it, the .DetectChanges() can't work, since you're using straight POCO classes without any change tracking, e.g. your au object doesn't have any way of knowing what's been changed - you basically need to do a property-by-property comparison yourself.

marc_s
I'm using POCO T4. So how do I save an entity once I have modified it? There doesn't seem to be any method like context.SaveDammit(entity);
brian b
A: 

Check this post for explanation how to save disconnected object.

Ladislav Mrnka