ORMOutOfSyncException in AuditUpdateOfExistingEntity

Posts   
 
    
mrbelk
User
Posts: 5
Joined: 08-Feb-2011
# Posted on: 08-Feb-2011 23:25:47   

I am experiencing an ORMOutOfSyncException in the AuditUpdateOfExistingEntity method of my auditor class. The exception is thrown when I attempt to access a property of the modified entity to populate a field in a custom Audit Info entity.

As far as I know, the Update SQL is correct and doesn't generate any exceptions when it's executed as part of updating a larger EntityCollection of objects.

Any advice would be appreciated.

Oh, we're using LLBLGenPro 2.6 and the Adapter pattern.

-MrB

MTrinder
User
Posts: 1461
Joined: 08-Oct-2008
# Posted on: 08-Feb-2011 23:31:19   

The ORMOutOfSyncException suggests that the entity has been saved, but not reloaded when saved, before the property is being accessed in the audit function. Would this be possible...?

If you post the code you are using we can take a look.

Matt

mrbelk
User
Posts: 5
Joined: 08-Feb-2011
# Posted on: 08-Feb-2011 23:35:06   

We have the "refreshSavedEntitiesAfterSave" parameter of the DataAccessAdapter.SaveEntityCollection set to true, but in my debugger output I do not notice that the SQL for re-fetching the entity is output to the Debug console.

Here is the code from our Auditor method:


        public override void AuditUpdateOfExistingEntity(IEntityCore entity)
        {
            if (_updates.Count == 0)
                return; //no data to show

            AuditInfoEntity auditInfo = new AuditInfoEntity(Guid.NewGuid());
            auditInfo.AffectedEntityType = entity.LLBLGenProEntityName;
            auditInfo.AffectedEntityTypeFriendly = ((CommonEntityBase)entity).EntityTypeFriendly;
            auditInfo.AffectedEntityId = ((CommonEntityBase)entity).EntityId;
            auditInfo.AffectedEntityIdFriendly = Utils.Trunc(((CommonEntityBase)entity).EntityIdFriendly, 80, false);
            auditInfo.ActionDateTime = DateTime.Now;
            auditInfo.ActionType = (int)AuditType.Updated;
            auditInfo.ActionData = GetActionData(entity, AuditType.Updated);
            auditInfo.UserId = ((UsersEntity)Thread.CurrentPrincipal.Identity).UserId;
            auditInfo.ParentEntityId = ((CommonEntityBase)entity).ParentEntityId;
            _auditInfoEntities.Add(auditInfo);
        }

The exception is being thrown in the line that attempts to resolve EntityIdFriendly, which is a custom property that formats 3 other properties from the underlying object.

-MrB

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 09-Feb-2011 02:44:51   

Hi MrB,

This is expected. This is why: 1. You update your entity in your GUI 2. The entity is actually updated in DB 3. AuditUpdateOfExistingEntity is called. At this point, the entity is outOfSync. 4. The entity is fetched back. 5. The transaction is committed (your entity save and the audit object)

So the problem is that you are accessing the entity's properties when it's in an OutOfSync state. This is expected. If you would get the unsaved entity the audit shouldn't be took place, and if you get the entity after the fetch-back, the entity won't contains the original data (DBValue). To overcome this the recommended way is to grab all you need about fields in the AuditEntityFieldSet method. See this: http://www.llblgen.com/TinyForum/Messages.aspx?ThreadID=10913

This can be easily done in your case. You can keep private variables in your auditor that stores the necessary data from the fields you want, you set those variables in the AuditEntityFieldSet method and then access them in the AuditUpdateOfExistingEntity method.

David Elizondo | LLBLGen Support Team
mrbelk
User
Posts: 5
Joined: 08-Feb-2011
# Posted on: 09-Feb-2011 14:44:46   

Hi daelmo,

I would generally agree with you except that a colleague of mine just performed the exact same procedure and was able to do this. It should be noted that this auditing mechanism is not new in this particular application. I have simply added a couple new data points to this particular entity that we have to capture.

Does that change your diagnosis?

-MrB

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 09-Feb-2011 15:30:38   

A change was made in the audit behavior: the audit of Insert and audit of Update actions are called right after the entity is saved and right before the entity is refetched from db. So, in the audit method the entity is not sync with db, that's why you receive the error. More info: http://llblgen.com/TinyForum/Messages.aspx?ThreadID=15879

So you have two options as I see:

A. (preferred) Use the Fields property and DBValue and CurrentValue as follows:

entity.Fields["TheFieldName"].CurrentValue

The benefit is that it's clear at code what value you are accessing (original value or new changed value).

B. Indicate that the entity is fetched so you wont receive any OutOfSync exception when accessing fields. (Related thread: Related thread: http://www.llblgen.com/TinyForum/Messages.aspx?ThreadID=16086)

entity.Fields.State = EntityState.Fetched;
mrbelk
User
Posts: 5
Joined: 08-Feb-2011
# Posted on: 09-Feb-2011 15:44:02   

Option (A) worked for me; but I am still confused as to why my colleague (who is using the same versions of LLBLGen) does not get this error when he performs the exact same procedure.

Thanks for the suggestions.

-MrB