locked
Refresh problem when overriding ObjectContext.SaveChanges RRS feed

  • Question

  • I am overriding tha SaveChanges method on the ObjextContext class. I am doing this to set some system fields like, ModifiedBy, CreatedBy, ect. I am doing it like this:

                foreach (var stateEntryEntity in objectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified)

                    .Where(entry => (entry.Entity is ICommonTable) && (!entry.IsRelationship)))

                {

                    ICommonTable commonTable = (ICommonTable)stateEntryEntity.Entity;

                    switch (stateEntryEntity.State)

                    {

                        case EntityState.Added:

                            commonTable.DocumentsExists = 0;

                            commonTable.VersionStamp = 1;

                            commonTable.CreatedDateTime = DataEntryConstants.NowWithSeconds;

                            commonTable.CreatedBy = Authentication.UserName;

                            break;

                        case EntityState.Modified:

                            commonTable.VersionStamp++;

                            commonTable.ModifiedDateTime = DataEntryConstants.NowWithSeconds;

                            commonTable.ModifiedBy = Authentication.UserName;

                            break;

                        case EntityState.Deleted:

                            break;

                    }

                }

     The values gets updated in the database, so that part is ok. The problem is on the client side. When I am adding a new object by calling DataServiceContext.AddToCourseAttendees and afterwards DataServiceContext.SaveChanges the server set properties like CreatedBy is being refreshed in the object on the client. 

    But when I am trying to update an object by calling DataServiceContext.UpdateObject and afterwards DataServiceContext.SaveChanges, the server set properties like ModifiedBy is not being refreshed on the client.

    Am I missing something?

    Thanks

    Henrik

    Tuesday, August 10, 2010 8:06 PM

Answers

  • Hi,

    You can use the GetEntityDescriptor(entity).EditLink to get the URL for that particular entity. And then you can use Execute to issue a GET to that URL. The MergeOption dance is still necessary (note that you should restore the MergeOption to its original value to avoid suprises).

    Out of cursiosity - why do you use Batch above if it seems that you're updating just a single entity? (that will cause unnecessary overhead in the request's payload)

    Thanks,


    Vitek Karas [MSFT]
    Thursday, August 12, 2010 9:34 AM
    Moderator

All replies

  • Hello Henrik,

     

    Are you using WCF Data Services, WCF services or WCF RIA Services?   For the entity classes, are you using general EntityObject, Self-Tracking entities or POCO entities?    Please provide us with more detailed information.   I will do my best to help.

     

    If it is convenient for you, would you mind sending us a demo project?   My mail: v-micsun@microsoft.com. 

     

    Good day!

     

     

    Best Regards,
    Lingzhi Sun

    MSDN Subscriber Support in Forum

    If you have any feedback on our support, please contact msdnmg@microsoft.com


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Wednesday, August 11, 2010 4:43 AM
    Moderator
  • Hello Lingzhi,

    I am using WCF Data Services and the entity classes are EntityObjects.

    I guess that you can reproduce it a very simple example, where you just have to create a partial class for the SaveChanges override. The ICommonTable interface is an interface which all my entities share. But you can just cast it to your own entity and set a value in a random property.

     

        public partial class MyEntities

        {

            public override int SaveChanges(System.Data.Objects.SaveOptions options)

            {

                foreach (var stateEntryEntity in this.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified)

                    .Where(entry => (entry.Entity is ICommonTable) && (!entry.IsRelationship)))

                {

                    ICommonTable commonTable = (ICommonTable)stateEntryEntity.Entity;

                    switch (stateEntryEntity.State)

                    {

                        case EntityState.Added:

                            commonTable.DocumentsExists = 0;

                            commonTable.VersionStamp = 1;

                            commonTable.CreatedDateTime = DataEntryConstants.NowWithSeconds;

                            commonTable.CreatedBy = Authentication.UserName;

                            break;

                        case EntityState.Modified:

                            commonTable.VersionStamp++;

                            commonTable.ModifiedDateTime = DataEntryConstants.NowWithSeconds;

                            commonTable.ModifiedBy = Authentication.UserName;

                            break;

                        case EntityState.Deleted:

                            break;

                    }

                }

     

                return base.SaveChanges(options);

            }

     

        }


    Thanks

    Henrik.

    Wednesday, August 11, 2010 7:33 AM
  • Hi,

    This is the current state of things in .NET 4.0. The "update" requests (MERGE or PUT) don't return the entity serialized in the payload from the server (you can see that using fiddler or something like that). POST does. So the client doesn't even recieve the updated properties. The only possible workaround is to issue a GET request from the client after the update (and don't forget to set the MergeOptions to the right value before the request).

    We know about this limitation currently and we're considering possible ways to fix this in future release.

    Thanks,


    Vitek Karas [MSFT]
    Wednesday, August 11, 2010 5:11 PM
    Moderator
  • Hi again,

    Thank you for your reply. How do I reload/refresh an entity? Do I have to execute the query again?

    Here is a code example:

                Employee emp = new Employee();

                emp = myCTX.Employees.Where(p => p.EmployeeId == "ABC").FirstOrDefault();

                emp.FullName = "My Name";

                myCTX.UpdateObject(emp);

                myCTX.SaveChanges(SaveChangesOptions.Batch);

                // Refresh Values

                myCTX.MergeOption = MergeOption.OverwriteChanges;

                // How do I reload the Employee entity?


    Thanks
    Henrik

    Thursday, August 12, 2010 9:01 AM
  • Hi,

    You can use the GetEntityDescriptor(entity).EditLink to get the URL for that particular entity. And then you can use Execute to issue a GET to that URL. The MergeOption dance is still necessary (note that you should restore the MergeOption to its original value to avoid suprises).

    Out of cursiosity - why do you use Batch above if it seems that you're updating just a single entity? (that will cause unnecessary overhead in the request's payload)

    Thanks,


    Vitek Karas [MSFT]
    Thursday, August 12, 2010 9:34 AM
    Moderator
  • Great thanks. Works perfect, I have just done this:

                myCTX.MergeOption = MergeOption.OverwriteChanges;

                Uri editUri = myCTX.GetEntityDescriptor(emp).EditLink;

                emp = ctxMindKey.Execute<Employee>(editUri).FirstOrDefault();

                myCTX.MergeOption = MergeOption.AppendOnly;


    I know about the Batch setting. But the lines has been cut out of larger piece of code, so it makes sense :-)

    Thanks
    Henrik

    Thursday, August 12, 2010 9:49 AM