Unrelated and out-of-scope entity picked up in save

Posts   
 
    
hotchill avatar
hotchill
User
Posts: 180
Joined: 22-Jan-2007
# Posted on: 09-Dec-2012 11:29:33   

Hi.

I am on sql server 2008 R2 and llblgen v3.5 final.

I have a method that adds a new action entity to an enquiry entity:

public static EnquiryActionEntity AddAction(EnquiryEntity enq) {
            var enquiryActionEntity = enq.Actions.AddNew();
            enquiryActionEntity.User = UserEntityService.GetCurrentUser();
            enquiryActionEntity.ActionUserId = enquiryActionEntity.User.UserId;
            enquiryActionEntity.When = DateTime.UtcNow;
            enq.LastUpdated = enquiryActionEntity.When;
            return enquiryActionEntity;
}

This method is called in a try block and if something goes wrong, the entity is removed:

} catch { // need to roll back adding of action and change of status
  accessEnquiry.Actions.Remove(action);
  // hack to get around bug - can't get rid of this action in later transaction with save of other entity
  action.IsNew = false;
  action.IsDirty = false;
  accessEnquiry.EnquiryStatus = oldEnquiryStatus;
  throw;
}

This is done iterating over a collection of enquries:

foreach (var accessEnquiryEntity in enquiriesToResolve) {
 try {
 EnquiryEntityService.ResolveAccessEnquiry(accessEnquiryEntity.EnquiryId);
} catch (Exception ex) {
..
}
}

If an entity fails, saving of the next enquiry entity in the collection fails because the incomplete action entity of the preceding enquiry entity is picked up. Here is the save method:

public static void UpdateAccessEnquiry(AccessEnquiryEntity accessEnquiry, UserAccessLevelEntity userAccessLevel, bool fullContactList) {
            try {
                if (fullContactList) PreProcessContacts(accessEnquiry);
                Logger.PreWayPointLogging("UpdateAccessEnquiry for user " + UserEntityService.GetCurrentUser().Login + " and call " + accessEnquiry.EnquiryId);
                using (var adapter = new DataAccessAdapter(WebConfigWrapper.DbConnectionString)) {
                    adapter.StartTransaction(IsolationLevel.ReadCommitted, "UpdateAccessEnquiry");
                    adapter.SaveEntity(accessEnquiry, true, true);
                    adapter.SaveEntity(userAccessLevel, true, true);
                    adapter.Commit();
                }
                Logger.PostWayPointLogging("UpdateAccessEnquiry for user " + UserEntityService.GetCurrentUser().Login + " and call " + accessEnquiry.EnquiryId);
            } catch (Exception ex) {
                var debugBuilder = new StringBuilder();
                debugBuilder.AppendFormat("An error occurred attempting to update enquiry {0} with action count: {1}.\n", accessEnquiry.EnquiryId, accessEnquiry.Actions.Count);
                foreach (var action in accessEnquiry.Actions) debugBuilder.AppendFormat("Action, message: '{0}', type: {1}.\n", action.Message ?? string.Empty, action.ActionType);
                Logger.Log(ex, debugBuilder.ToString());
                throw;
            }
        }

The line adapter.SaveEntity(accessEnquiry, true, true); fails. I have debugged and see that there is only one action entity in the Actions collection of the enquiry entity. Despite this, as the attached trace shows, the action entity of the preceding enquiry is picked up in the save (see FK of insert statement last in the trace).

I added thes lines as a workaround, but would like to get rid of this:

action.IsNew = false;
action.IsDirty = false;

Why is the unrelated and out-of-scope action entity picked up by the save?

Thanks, Tore.

hotchill avatar
hotchill
User
Posts: 180
Joined: 22-Jan-2007
# Posted on: 09-Dec-2012 11:37:01   

hmm...I think it is because of this line:

enquiryActionEntity.User = UserEntityService.GetCurrentUser();

We just added session cache for this user entity.

hotchill avatar
hotchill
User
Posts: 180
Joined: 22-Jan-2007
# Posted on: 09-Dec-2012 11:44:37   

yeah, that was it. Sorry, please close this.

I have this roll back now:

} catch { // need to roll back adding of action and change of status
accessEnquiry.Actions.Remove(action);
action.User.EnquiryActions.Remove(action);
accessEnquiry.EnquiryStatus = oldEnquiryStatus;
throw;
}