MylesRip
MylesRip

Reputation: 1352

SaveChangesAsync fails and callback not executed (IdeaBlade)

I inherited an application built on Silverlight 4 using IdeaBlade from DevForce 2010 version 6.1.15.0. The backend database is SQL Server 2008. In tracking down some updates/inserts that weren't working, I discovered that I was getting the following error from the call to IdeaBlade.EntityModel.EntityManager.SaveChangesAsync().

"An entity or entities containing a referenced temporary Id is missing from the list of entities provided. Missing entities include: Revision: -100. See exception members for more details"

Additional digging uncovered the following additional information.

"The UPDATE statement conflicted with the FOREIGN KEY constraint "FK_valuation_revision". The conflict occurred in database "XX", table "Revision", column 'RevisionID'. The statement has been terminated."

In digging deeper, I discovered the following:

  1. The two main classes involved are: Valuation and Revision
  2. Valuation has a collection of Revisions. On the database, this is represented by a FK on the Revision table (not null) that references the PK of the Valuation table.
  3. In addition, Valuation has a reference to the CurrentRevision. This is represented on the database as a FK on the Valuation table (can be null if there are no revisions) that references the PK on the Revision table.
  4. In the problem code, a new Revision object is created like so:

    myNewRevision = new Revision { Valuation = myExistingValuation };

    At this point, myNewRevision is an IdeaBlade.EntityModel.Entity with an EntityState of "Added".

  5. After a couple of additional changes to the object, the following code is executed.

    EntityManager.AddEntity(myNewRevision);

    The above call to AddEntity doesn't seem to accomplish anything as the state of MyNewRevision is the same after the call as it is before the call.

  6. Next an attempt is made to save the newly created Revision object.

    SaveChangesAsync(new[] { myNewRevision }, null, RevisionCallback, null);

    The above statement is within a try...catch block and no error is thrown, but the RevisionCallback routine is never executed. Also the EntityState of myNewRevision is still "Added" and the key is still showing as -100.

  7. Then the existing Valuation object is updated with the reference to the new Revision.

    myExistingValuation.CurrentRevision = myNewRevision;

    This causes the EntityState of myExistingValuation to change from "Unchanged" to "Modified".

  8. Finally, the code tries to save the changes to the Valuation object.

    SaveChangesAsync(new[] { myExistingValuation }, null, ValuationCallback, null);

  9. The result of this call is that the ValuationCallback is called, but myExistingValuation is still showing as "Modified", the reference to myExistingValuation.CurrentRevision still refers to myNewRevision with a key of -100 and an EntityState of "Added". The EntitySaveOperation object returned to the callback method has Exception == null, HasError = true, and the error is the one described at the beginning of this question. That is,

    "An entity or entities containing a referenced temporary Id is missing from the list of entities provided. Missing entities include: Revision: -100. See exception members for more details"

    and

    "The UPDATE statement conflicted with the FOREIGN KEY constraint "FK_valuation_revision". The conflict occurred in database "XX", table "Revision", column 'RevisionID'. The statement has been terminated."

    The database is not updated.

Any suggestions? Why doesn't the callback routine from the first call to SaveChangesAsync get executed? How can I get the updates to work?

Upvotes: 0

Views: 795

Answers (1)

Kim Johnson
Kim Johnson

Reputation: 1227

It's odd that the RevisionCallback isn't called, but it's possible the async method hasn't completed when you do the next steps.

You can't use try/catch with the async methods here, as DevForce 2010 doesn't use the newer task-based async pattern; so exceptions will be returned to your callback or completion handler, or possibly to an EntityServerError handler if one is set up for the EntityManager.

DevForce will by default save all changes to entities in cache unless you specify a save list, but that list doesn't have to contain only one item. When you do a save of entities with temporary ids, all entities with a temporary PK or FK need to be in the save list passed to SaveChangesAsync. DevForce will automatically handle the fixup to the FK after the save completes successfully.

Is there any reason you can't do something like the following instead:

myNewRevision = new Revision { Valuation = myExistingValuation };
myExistingValuation.CurrentRevision = myNewRevision; 
SaveChangesAsync(ValuationCallback);

Upvotes: 0

Related Questions