Print Page | Close Window

Forcing early ID Fixup

Printed From: IdeaBlade
Category: DevForce
Forum Name: DevForce 2010
Forum Discription: For .NET 4.0
URL: http://www.ideablade.com/forum/forum_posts.asp?TID=3465
Printed Date: 13-May-2026 at 5:35am


Topic: Forcing early ID Fixup
Posted By: stephenmcd1
Subject: Forcing early ID Fixup
Date Posted: 30-May-2012 at 11:52am
I'm looking for a way to force ID Fixup to happen slightly earlier during the save process.  We have a custom EntityServerSaveInterceptor and we need to have some logic in there that access the 'real' IDs for entities before they get saved.  I've tried code such as this but it doesn't work as I would expect:
    public class SaveInspector : EntityServerSaveInterceptor
    {
        protected override bool ExecuteSave()
        {
            //See if any 'Contacts' where just added
            var newContacts = EntityManager.FindEntities<Contact>(EntityState.Added).ToList();
            
            //If so, do extra processing
            if (newContacts.Count > 0)
            {
                //Force all the temp IDs to be converted to real ones
                EntityManager.ForceIdFixup();

                foreach (var newContact in newContacts)
                {
                    var realId = newContact.ID;
                    //Do something with realID

                    //But at this point, the ID hasn't been fixed up
                    
                    //If I look at newContact.EntityAspect.HasTemporaryEntityKey in the debugger, it is still True
                }
            }

            //Continue on as normal
            return base.ExecuteSave();

            //Now the newContact has the real ID but it's too late for me at this point

        }
    }

Is that a bug in ForceIdFixup?  I don't really see how I might be calling it wrong - seems like a pretty straightforward method!  And I assume my custom IIdGenerator class is correct because I haven't had any problems with it - and once I call base.Execute save, my IIdGenerator finally does get called and the real ID is available.

Thanks,
-Stephen



Replies:
Posted By: DenisK
Date Posted: 01-Jun-2012 at 12:55am
Hi Stephen,

That should have worked. Here's a very simple SL4 solution using 6.1.7 to prove it. 

http://www.ideablade.com/forum/uploads/912/SL_T11899.zip - uploads/912/SL_T11899.zip

It's using the NumericIdGenerator supplied here.  http://drc.ideablade.com/xwiki/bin/view/Documentation/code-sample-idgenerator - http://drc.ideablade.com/xwiki/bin/view/Documentation/code-sample-idgenerator

Note: You'll also need to download the Sql script supplied above to create the dbo.NextId table in the NorthwindIB db to get the next real id.

Perhaps you can help me see what's different between my IdGenerator and yours. If you'd like, you can also send me your IdGenerator class and any other script that's required. I'll try to debug them as well here.


Posted By: stephenmcd1
Date Posted: 01-Jun-2012 at 10:54am
Thanks for the sample application.  I was able to find out why my implementation wasn't working but this brings up a few other issues.

It appears that the reason my IIdGenerator wasn't working with ForceIdFixup is because my class didn't have DataContract and DataMember attributes anywhere.  It appears that I need to be able to serialize the IIdGenerator.TempIds property from the client to the server.  Without doing that, the call to ForceIdFixup looks like it just asks my IIdGenerator if it has any TempIds and since that didn't get serialized, my generator says it doesn't have any temp IDs so nothing happens.

The first question I have is why I need to make the properties be serializable?  Whatever 'normal' fixup happens by default during save doesn't need them to be serializable (in our code they haven't been serializable since we made this class and our IdGenerator has always worked - it's only now that we want to force the fixup to happen earlier that I'm needing to make them serializable).  It's not a huge deal to make them serializable (although, it does require making things that used to read-only now be publicaly setable....and adding a new assembly reference to System.Runtime.Serialization which is a bit sad).  I'm wondering if maybe this is just a bug in the ForceIdFixup method?  I noticed that the comments for the property in the supplied NumericIdGenerator example even seem to suggest that you shouldn't need to serialize this....it says it's called on the client (which makes sense to me....it's the call on the server that confuses me):
    /// <summary>
    /// Called by DevForce on the client to retrieve a collection of the temporary Id values generated since
    /// the last <see cref="Reset"/> call.  
    /// </summary>
    /// <remarks>
    /// Be sure to maintain the collection of temporary Ids generated in <see cref="GetNextTempId"/>. 
    /// </remarks>
    public UniqueIdCollection TempIds {
      get { return _tempIds; }
    }
Another concern that I have comes from the comments on the EntityManager.ForceIdFixup() method itself:
/// <summary>
/// Force an immediate update of all auto-generated IDs.
/// </summary>
/// <remarks>
/// Auto-generated temporary IDs are automatically "fixed up" during save processing.  You
/// can force that fixup to be done prior to a save by calling this method.
/// An exception will be thrown if any entity properties whose schema definition
/// has a <b>StoreGeneratedPattern="identity"</b> attribute are pending fixup,
/// since these IDs can only be assigned during a save operation.
/// </remarks>
public void ForceIdFixup() { ... }
I don't think we use many identity columns in our database but I think there might be some.  And that warning scares me :-).  What happens if I want to force ID fixup to happen on some entities?  Currently, I'm just going to force fixup on everything because that was the first method I found.  But then if I happen to have other entities in the Entity Manager that are being saved and they have identity columns.....well, I don't want my save to break.  Is there a way to force fixup on a particular entity and/or property?  Or to force it on all properties except the identity ones?

Thanks!


Posted By: stephenmcd1
Date Posted: 01-Jun-2012 at 11:09am
Also, another problem that I noticed.  In your sample code (and in my code), the GetRealIdMap method will be called twice for each Save.  So in your sample app, I only ever get odd IDs - all the even IDs get 'burned'.  So instead of having Regions with IDs of: 1, 2, 3, 4 - they are 1, 3, 5.  It may not be a critical problem but we do have some really large tables and generating two IDs and then throwing one away every time could start to be a problem.


Posted By: stephenmcd1
Date Posted: 01-Jun-2012 at 2:58pm

After more testing, it looks like the duplicate calls to GetRealIdMap are worse than I thought.  It's not just causing some Ids to be wasted, it ends up breaking much worse.  Once the save finishes, I end up with duplicate entities in the client's Entity Manager (by duplicate, I mean that the original item with the temporary ID and a new item with the real ID are both in there)!

Note: I noticed in the sample app you attached above, the MyEntityServeSaveManager.ValidateSave() method always returns false!?!  I'm not sure why that is done.....that basically cancels the save so doesn't really demonstrate that the ForceIdFixup method works.  If you change it so ValidateSave returns true (and also comment out the call to ForceidFixupOnClient since I'm not interested in that), you'll see that GetRealIdMap gets called multiple times and then when the SaveChangesAsync method returns, there will be two Regions in the Entity Manager instead of one.

:-(



Posted By: DenisK
Date Posted: 01-Jun-2012 at 5:17pm
Hi Stephen,

Re: Serialization attributes,

I commented out both DataContract and DataMember attributes in my NumericIdGenerator and my ForceIdFixup call on the server still works. Upon further investigation, the EntityManager has an internal TempIds property that gets shipped along to the server and it's this property, not the one in the IdGenerator, that gets used on the server. It looks like we still need more clues as to why you're experiencing things differently with your code. Can I ask for your IdGenerator? You can PM me.

Re: Only force fixup on certain entities,

Here are some suggestions:

1. Do partial client side saves and use SaveOptions.FixupTempIds. See  http://drc.ideablade.com/xwiki/bin/view/Documentation/save-methods#HTheSaveOptionsclass - http://drc.ideablade.com/xwiki/bin/view/Documentation/save-methods#HTheSaveOptionsclass

2. Or if you want to do this on the save interceptor, you can try to create a separate EM containing just the non-identity entities and do fixup on them. But this may prove to be troublesome if you have relationships between identity and non-identity entities. 

If neither of the above works, perhaps you can give us the broader use case for this so we can give better suggestions.

Re: GetRealIdMap being called twice,

I was able to reproduce this behavior. I'll file a bug report for this. I was returning false in my ValidateSave since at that time, I wanted to only test the ForceIdFixup call without actually saving.

I just want to make sure we're seeing the same issue. In my case, I can see this method called twice and I can see duplicate entities in my client side EM after the save. However, the duplicate entities both have different real ids and not a temp id and a real id as you said. Could you make sure that you're seeing the same thing?


Posted By: stephenmcd1
Date Posted: 01-Jun-2012 at 9:46pm
Sorry this post is getting so complicated that it requires separate headings!

Serialization Attributes

Okay, I'll take a look more in depth.  All I noticed was that adding those attributes and making some of my private fields setable (to make the serializer happy) got it working.  But maybe I inadvertently made some other changes at the same time.  I'll double check that.  And I can send along my IdGenerator (I'm out of the office right now so it might not be until Monday).

Fixup on certain entities

Partial saves won't really work because the entity that needs it's Id generated has a number of child tables and some other relations to it - trying to save just a small part of the graph would be a problem.  Not to mention the danger of not having a transactional save anymore (although, I suppose I could have a custom server method to do multiple saves in one transaction but that sounds like it would be a real pain). Trying to copy the entities to their own entity manager on the server seems like it might not work just because of all our relationships.  Although, I'm willing to try it.  How would I actually do that though.  I copy some entities into a new entity manager and then just force ID fixup on them?  Then import them back into the original entity manager so they can actually get saved?  I can't just save the second entity manager because I've already been with the "Recursive saves are not allowed" thing.  If I did the merge, then I'd be worried that the fixup stuff wouldn't happen on the client then.....as I noticed when I tried generating real IDs myself I ran into problems.  Which reminds me of something I tried that I might as well mention...

In some of my failed attempts, I even tried generating the real ID myself for the one entity that I needed.  That all seemed to work ok on the server, but when the save made its way back to the Silverlight client, the Ids that I 'manually fixed up' didn't get fixed up.  I imagine that me going behind DevForce's back on the server causes problems on the client.  So I abandoned that thought.

I can give you the full picture of the scenario I'm trying to accomplish.  It's not exactly a 'pretty' scenario and I wish things were different.....but we're dealing with a legacy database and my hands are tied when it comes to a lot of this.

We have a gigantic database that we've had to split up into many different models for performance reasons (mostly the EF Visual Designer does not like trying to display hundreds of tables at once).  But there are cases where we have common entities that we'd like to be shared across all the models.  For example, our application has the notion of things called "Notes" (notes include things like text, file attachments, etc.).  You can put notes on a lot of our entities.  And they are on a lot of entities that are in different models.

We can fairly easily get DevForce to make the correction associations / navigation between entities in different models and that is great.  The only trouble comes when we go to save because we can't (at least not yet) fool Entity Framework into thinking there are associations between models so it does the saves in whatever order it feels like.  But in our case, that doesn't work because we need the saves to happen in a particular order.  That is why I'm trying to do all this crazy temp ID fixup stuff.  Here is a simplified version of our data model (hopefully I can express it in text form):

Entity1 Table
Entity1ID (PK)
NoteID (FK to Note Table)
...

Entity32 Table
Entity32ID (PK)
NoteID (FK to Note Table)
...

Note Table
NoteID (PK)
(no other columns - this is a weird table)

NoteEntry Table
NoteID (PK)
EntryNumber (PK)
EntryText


Now imagine the case where the user adds a new Entity14 along with a Note Entry.  We'll end up sending 3 entities to the server to be saved:

Entity14 - Entity14ID = -100, NoteID = -101
Note - NoteID = -101
NoteEntry - NoteID = -101, EntryNumber = 1

From an RI standpoint, we need the Note to be saved first (because it's a FK in those other two entities) but we can't really force EF to do the saves in any particular order (or at least, we haven't found an easy way.  If anybody has thoughts, we'd love to hear them!!).

So what my "solution" was is to force IdFixup to happen right before save, then I can just do the insert into the Note table myself out-of-band.  I mark the Note entity as not having any pending changes and then I let DevForce do the save as normal.  It sees it only needs to save the Entity14 and NoteEntry but at that point the save order doesn't matter.

It sounds very hacky I know.  The code itself doesn't end up being that bad.  And other than the duplicate entities showing up on the client after the save (which I can temporarily hack around until you guys fix that), it all seems to work.  But then there is the looming scare that we might have an identity column in there somewhere and so the ForceIdFixup method will throw an exception and thwart my crazy hacks.

That's the overall problem I'm trying to solve.  I know it's a lot of information but hopefully it makes sense.

GetRealIdMap being called twice

You are right, none of the two entities have the old temporary ID.  In my tests in our application, I was looking at things through the UI and I guess maybe property change notification didn't get fired on one of the duplicates so it was still showing as having the old, temporary ID.  But when I looked at it in the debugger, I saw that it did have the new ID.  So yes, seems like we are seeing the same thing.

Thanks for all the help!  I know this is not a simple issue.


Posted By: DenisK
Date Posted: 04-Jun-2012 at 7:39pm
Hi Stephen,

Fixup on certain entities

Thank you for the detailed write up on this. Unfortunately, even if your ForceIdFixup seems to work for now, it doesn't actually address the core problem. The main issue lies with DevForce saving entities across different data source keys. DF groups the entities to be saved by data source keys and then calls EF to save for that particular key. The order in which the data source keys are processed is undefined.

DF could, in theory, handle relationships across data source keys and intelligently identify the order in which data source keys should be processed but as you might have guessed, this is not a trivial problem.

We tried to come up with a reasonable workaround for this but for now, we can only think of 2 things.

1. As soon as you create a Note entity, save it first just so you can get its real Id and use it with your other Entity*. You can save it again later as its other properties get populated.

or

2. Re-design the model layer such that you don't have dependencies across different data source keys. Yes, you will end up with duplicate common entities (or duplicate common Note entities in this case) but with shared partial classes and some pre-processor directives, you can still avoid duplicating your codes. I realize that this option is more of an ideal best practice advice if you're still early in the architectural phase but I'd just like to put it on the table.

GetRealIdMap being called 

Even if this "bug" is fixed, it still won't solve the issue as explained above so we're not considering this bug a high priority for now.

This is what I have for now. I hope that by sharing the core problem we're trying to tackle, you can also come up with your own creative solution :)


Posted By: stephenmcd1
Date Posted: 06-Jun-2012 at 11:41am
Thanks for the suggestions.  Suggestion #1 is basically what I'm trying to accomplish (save the Note entity first by itself and then save the other guys).  The thing that I very much dislike about the specifics of your recommendation is that I lose transaction integrity.  I have to go save a Note entity basically right away when somebody starts editing one of my entities.  But if they decide to not save their changes, I'm stuck with the Note row in the database.  I can try to delete it if the user cancels but that is very error prone.  Also, I'm in a Silverlight application so adding lots of asynchronous calls to 'prepare for edit' and 'cancelling edit' make things very complicated.

Instead, I was trying to save the Note entity early but still during the 'normal' save so I can have it in the same transaction (and do it synchronously).  And if the ForceIdFixup worked as I expected, I think this would be a viable solution.  DevForce can't possibly know what order to save the entities (I agree), but my code knows all this so my code can do that.  The solution I was going for was something like this bit of pseudo-code:
    protected override bool ExecuteSave()
    {
        StartTransaction();
        ForceIdFixup();
        int newNoteRealId = FindTheNewNote().Id;
        InsertRowForNote(newNoteRealId);
        PerformNormalSave();
        CommitTransaction();
    }

The  InsertRowForNote code is a bit awkward since DevForce doesn't support recursive saves but that's not too hard to get around.  With a solution like that, I have nice transactional integrity without having to do too much work.

I'm a bit disheartened that the bug won't be considered a high priority (and not sure why bug was put in quotes - it seems like a pretty straight forward bug to me - albeit an obscure one [but I'm finding obscure bugs all the time! :-)]).  I suppose calling ForceIdFixup during the Save is just not a supported use case of that method?  If so, that should probably be documented.  But still, being able to know the real ID of an entity before it gets persisted sure seems like something worth supporting.


Posted By: DenisK
Date Posted: 07-Jun-2012 at 1:14pm
Hi Stephen,

I suppose calling ForceIdFixup during the Save is just not a supported use case of that method?

That is correct. It wasn't intended to be called from the server, which means there are issues if we're going to support it. The double call to GetRealIdMap is just one of them.

One other suggestion is to not use Temp IDs at all for the Note entity. Assign it a real id manually as soon as you create one but without using ForceIdFixup. I imagine that you can query your NextId table and get the real id this way.

Let us know if this is a workable solution for you. We'll think of another one if it's not.


Posted By: stephenmcd1
Date Posted: 13-Jun-2012 at 5:08pm
Thanks for the update.

I think your suggestion might be my only way to go.  In the worst case, I end up 'burning' a real ID and then have a stranded Note row in the database (which is not the end of the world).  One change I made, instead of getting the real ID right away when the entity is created, I've moved that up until the last minute....once the user clicks 'Save', I go get a real ID, assign it and then actually do the normal save.  

However, I'm running into an issue.  I think its the same one we saw before - where there ends up being 'duplicate' entities in the entity manager (I use the term duplicate loosely since they are different instances in memory but represent the same thing logically - and somehow end up having the same key [didn't know you could have duplicate keys in an entity manager!]).  You had mentioned that you would file that bug....hopefully that isn't the one that became lower priority.  Here is what I'm doing so we can see if it is the same bug or not.

As a reminder, my ultimate goal isn't just finding a way to generate the Temp IDs.  Its to be able to do a two-part save basically since I'm trying to save things in different EF models.

Assuming I'm trying to save a new Company entity (the parent) along with a new Note entity and a new NoteEntry.  I have logic like the following:
public void Test()
{
    var em = new EntityManager();

    //Create a parent entity, a note and a note entry
    var parentEntity = em.CreateEntity<Company>();
    var note = em.CreateEntity<Note>();
    var noteEntry = em.CreateEntity<NoteEntry>();

    //Add the parent to the entity manager
    parentEntity.EntityAspect.AddToManager();

    //Assign the note to the parent and add the note entry to the note
    parentEntity.NoteControl = note;
    note.Notes.Add(noteEntry);

    //At this point, all the entities have the temporary NoteID
    Assert(note.NoteID == -100);
    Assert(noteEntry.NoteID == -100);
    Assert(parentEntity.NoteID == -100);

    //Get a real Id to use for note (we don't care how this happens)
    int newNoteSid = GetNextIdSomehow();

    //Because I can't control the save order, I want to actually save the Note entity first so none of 
    //   the database triggers complain.
    //This method adds a row to the note table - again, we don't care how this happens
    InsertRowInNoteTableSomehow(id);

    //Assign the new note sid to the Note
    note.NoteID = newNoteSid;

    //Sanity check: The new note sid got cascaded to all the entities
    Assert(note.NoteID == newNoteSid);
    Assert(noteEntry.NoteID == newNoteSid);
    Assert(parentEntity.NoteID == newNoteSid);

    //Since we already added a row to the note table (behind our back), we accept the changes
    //   on the note entity.  This way, we don't try to do an extra INSERT statement that would cause
    //   a failure of duplicate primary keys in the Note table
    //NOTE: This seems to be the line that gets DevForce confused.  Nothing breaks yet, but it will
    //Also, I tried doing a SetModified() instead of AcceptChanges() and that broke also.
    note.EntityAspect.AcceptChanges();

    //Do the save - at this point, it's only the parent entity and the note entry
    em.SaveChangesAsync(op =>
    {
        //Sanity check: Let's get all the note entries.  There should only be one
        var noteEntries = em.FindEntities<NoteEntry>().ToList();

        //Assert fails - there are actually two entries!  They both have the same key but one is 
        //   Unchanged and the other is in Added state.
        Assert(noteEntries.Count == 1);
    });
}


Posted By: DenisK
Date Posted: 14-Jun-2012 at 5:48pm
Hi Stephen.,

Actually, my suggestion above is to not use temp ids at all. I see that you're still using temp ids here. Since we're sort of "cheating" in inserting the Note entity here and then assigning the real id, I'm not exactly surprised that there are problems.

Try not to use temp ids at all and see how it goes. Something like below,

var note = em.CreateEntity<Note>();
//Get a real Id to use for note (we don't care how this happens)
int newNoteSid = GetNextIdSomehow();
note.NoteID = newNoteSid;


Posted By: stephenmcd1
Date Posted: 15-Jun-2012 at 4:58pm
I really don't want to be trying to get a real ID so early.  Our application isn't really structured for operations like that to be asynchronous.  Also, I don't really want to be committing rows to the database as a user edits an item.

I tried using my own version of temporary IDs but I still had the problem.  Instead of using any of the standard DevForce Temp ID generation, I just hardcoded a magic number when I first create my Note entity.  Then at save time, I do my own fixup between the magic number and the 'real' number that I got.  I would have expected at least that much to work.  No real temp Ids involved at all.

Surely I should be able to change key values of entities as long as it is before I've saved them?  I shouldn't need to do all my setup before I add child entities?


Posted By: stephenmcd1
Date Posted: 18-Jun-2012 at 11:10am
So I did a bit more digging and debugging (I figure that if I can narrow down the cause it might make it more likely that it gets fixed :-)).  I found two problems that I think both stem from a similar problem.  I tried to simplify my examples as much as possible.

1. Changing a PK only cascades that new value to direct children but not grand-children.

I took the NorthwindIB database and added an extra table so that I could have a 3-level relationship.  The model now looks like this:

And I have test code like the following.  I understand that I could get things to work by starting off with using the 'final' Id, but in our app, we simply can't do (I suppose we could not-so-simply try to get that but it still seems like this code should work and that it is a bug).
//Create an order
var order = em.CreateEntity<Order>();
order.EntityAspect.AddToManager();
            
//For now, lets start with 111 for the PK - this will change later
order.OrderID = 111;
            
//Create an order detail and add it to the Order
var orderDetail = em.CreateEntity<OrderDetail>();
orderDetail.EntityAspect.AddToManager();
orderDetail.ProductID = 222;
order.OrderDetails.Add(orderDetail);

//Create a third-level entity - an "Extra Detail" of the Order Detail and add it
var extraDetail = em.CreateEntity<OrderDetailExtraDetail>();
extraDetail.EntityAspect.AddToManager();
extraDetail.DetailID = 333;
orderDetail.OrderDetailExtraDetails.Add(extraDetail);

//Set the top-most entity's ID
order.OrderID = 999;

//Sanity check
DebugFns.Assert(order.OrderID == 999);

//Make sure the value cascaded down to the order detail
DebugFns.Assert(orderDetail.OrderID == 999);

//Make sure the value cascaded down to the extra detail
//FAIL: extraDetail.OrderID is still 111
DebugFns.Assert(extraDetail.OrderID == 999);

2. Changing the PK of the parent cascades to direct children but doesn't update their location in the EntityGroup._entityKeyMap dictionary

This one might not be quite as straight forward as #1 since it involves private / internal state :-).  But it seems to be the underlying cause behind getting duplicate entries in the entity manager (and I can imagine it might break other stuff as well).  Since the sample code I'm giving to reproduce the problem uses reflection to get at internal state, I know it might be a little bit sketchy.  I'm like 60% sure that this is a bug though (the other 40% is that I could just be wrong about how that dictionary is used)
//Create an order
var order = em.CreateEntity<Order>();
order.EntityAspect.AddToManager();

//For now, lets start with 111 for the PK - this will change later
order.OrderID = 111;

//Create an order detail and add it to the Order
var orderDetail = em.CreateEntity<OrderDetail>();
orderDetail.EntityAspect.AddToManager();
orderDetail.ProductID = 222;
order.OrderDetails.Add(orderDetail);

//Set the top-most entity's ID
order.OrderID = 999;

//Get the Entity Group for Order Details
var orderDetailGroup = em.GetEntityGroup<OrderDetail>();

//A bit of a hack to grab the entityKeyMap dictionary from the Order Details EntityGroup
var keyMap = (Dictionary<EntityKey, EntityAspect>)
                typeof (EntityGroup)
                    .GetField("_entityKeyMap", BindingFlags.Instance | BindingFlags.NonPublic)
                    .GetValue(orderDetailGroup);

//The dictionary should contain the order details Entity Key
//Fail: It does not include it!
DebugFns.Assert(keyMap.ContainsKey(orderDetail.EntityAspect.EntityKey));

//If we ignore the previous failure, we'll see another failure here.  The dictionary
//   still has an entry for the old (111) value!
DebugFns.Assert(keyMap.ContainsKey(new EntityKey(typeof (OrderDetail), 111, 222)) == false);

Of course, normally I wouldn't be looking into internal / private state of DevForce objects but I think this is what caused the duplicate entities.  After the save, a Merge happens from the saved entities into the original entity manager.  Since the original entity manager has my entity listed under the wrong key in the dictionary, the merge doesn't see it and so adds the saved entity to the entity group - and then we end up with two in there!

I know changing PK values isn't the most common thing to do.  But it seems perfectly valid to do that as long as the entity is still in an Added state (in fact, I saw lots of code checks that DevForce does to block you from changing the PK but not when it is in the Added state).


Posted By: DenisK
Date Posted: 18-Jun-2012 at 4:25pm
Hi Stephen,

Thanks for narrowing down the problem. It really helps a lot in understanding what you're doing.

1. Changing a PK only cascades that new value to direct children but not grand-children.

DevForce never supports grandchildren cascading with this use case. Sorry for the short answer here but unfortunately you have to do this manually.

2. Changing the PK of the parent cascades to direct children but doesn't update their location in the EntityGroup._entityKeyMap dictionary

Nice job in finding out what the problem is here. On one hand, you are right that it is somewhat reasonable to allow PK to be changed when an entity is still in an Added state, but on the other, you're also right that this is not the most common thing to do so it's conceivable that we might have a bug or two. 

In any case, I'll open a bug report. Also, just as an FYI, without using reflection, you can also write the unit test in the following way.

order.OrderID = 999;
Assert.IsTrue(em.IsEntityLoaded(orderDetail.EntityAspect.EntityKey), "Should return true");

I'll keep you updated.


Posted By: DenisK
Date Posted: 20-Jun-2012 at 3:33pm
Hi Stephen,

We've fixed issue #2 above. I've PM'ed you an EAP for 6.1.8. Please let us know if you're still having problems.



Print Page | Close Window