- Home
- LLBLGen Pro
- LLBLGen Pro Runtime Framework
Collections going crazy
Joined: 23-Jan-2006
Here's segment of code that works just perfectly on insert but on update it starts acting weird. In this example view.RoomCollection contains a EntityCollection<RoomEntity>. entity is a parent of Room and contains a collection on a property called Room which is loaded using prefetch paths when the entity is used for an update. I collect a combination of old rooms (entity.Room) and newly created rooms in view.RoomCollection. Before I save the "entity" I try to walk through the view.RoomCollection and ensure that each room is associated with its parent unit.
Again, when entity.IsNew = true this works just fine but if this entity.IsNew = false and this is an update, an exception is thrown stating that the collection has been modified. I tried this using a for loop instead of foreach and each time i hit the line - entity.Room.Add(room) the view.RoomCollection.Count is reduced by one!!!??? During debug I have ensured that view.RoomCollection != entity.Room but for some reason associating a room with its parent seems to remove it from the view.RoomCollection. Please help me, this has been making me pull my hair out.
EntityCollection<RoomEntity> currentRooms = view.RoomCollection;
foreach (RoomEntity room in currentRooms)
{
if (entity.Room.IndexOf(room) < 0)
{
entity.Room.Add(room);
}
}
KastroNYC wrote:
Here's segment of code that works just perfectly on insert but on update it starts acting weird. In this example view.RoomCollection contains a EntityCollection<RoomEntity>. entity is a parent of Room and contains a collection on a property called Room which is loaded using prefetch paths when the entity is used for an update. I collect a combination of old rooms (entity.Room) and newly created rooms in view.RoomCollection. Before I save the "entity" I try to walk through the view.RoomCollection and ensure that each room is associated with its parent unit.
Again, when entity.IsNew = true this works just fine but if this entity.IsNew = false and this is an update, an exception is thrown stating that the collection has been modified. I tried this using a for loop instead of foreach and each time i hit the line - entity.Room.Add(room) the view.RoomCollection.Count is reduced by one!!!??? During debug I have ensured that view.RoomCollection != entity.Room but for some reason associating a room with its parent seems to remove it from the view.RoomCollection. Please help me, this has been making me pull my hair out.
EntityCollection<RoomEntity> currentRooms = view.RoomCollection; foreach (RoomEntity room in currentRooms) { if (entity.Room.IndexOf(room) < 0) { entity.Room.Add(room); } }
entity.Room.Add(room); also does: room.Entity = entity; where .Entity is of course the fieldmapped onto the relation entity - Room.
e.g. room == order, and entity == customer. so when I do: customer.Orders.Add(myOrder); it also does: myOrder.Customer = customer;
IF room.Entity already was an instance, namely view as it is in that collection, it will first dereference view from room as it can be referenced to only one. (m:1 relation).
So, if your routine is meant to move room from one parent to the other, it should be done a little differently. If your routine is meant to do something else, please explain further. Also, what are 'view' and 'entity'... it's unclear now.
Joined: 23-Jan-2006
In this example - view == a web form which has a property called RoomCollection and entity == the target parent of each room in the collection. What seems to be happening is on an insert everything works fine but on an update, whenever I add a room to the RoomCollection the room.Unit is being set somehow it seems automatically.
So here's what I hope will be a bit clearer explanation:
view == a web form
view.RoomCollection == the web forms - EntityCollection<RoomEntity> property
entity == the target parent of all rooms in the view.RoomCollection (so this is the entity which I want to be the parent of all rooms in the collection
Scenario:
1) view (web form) is loaded and view.RoomCollection is bound to entity.Room
2) user adds two rooms to the view.RoomCollection
2*) during debug I check each room in the view.RoomCollection and all rooms seem to have an associated parent even the new ones which were just added - it seems that because the view.RoomCollection contains a list of RoomEntity which are associated with an entity, adding a new room to the collection is automatically associating the new room with the parent entity of all other rooms in the collection. This wouldn't be a problem if when I called save on the parent entity it noticed these newly related items but for some reason it doesn't. I would expect this to work the same way as insert where if any association exists between the target of the save and related entities those related entities would be saved too but this doesn't seem to be the case on update.
3) I run the segment of code from my last post attempting to associate any newly added rooms to the entity and I get the error
I really hope this explains the problem a little better. At this point I'd be willing to pay for a tech support call to help me understand this. Thanks
KastroNYC wrote:
In this example - view == a web form which has a property called RoomCollection and entity == the target parent of each room in the collection. What seems to be happening is on an insert everything works fine but on an update, whenever I add a room to the RoomCollection the room.Unit is being set somehow it seems automatically.
So here's what I hope will be a bit clearer explanation:
view == a web form
view.RoomCollection == the web forms - EntityCollection<RoomEntity> property
entity == the target parent of all rooms in the view.RoomCollection (so this is the entity which I want to be the parent of all rooms in the collection
Scenario:
1) view (web form) is loaded and view.RoomCollection is bound to entity.Room
Ok, so view.RoowCollection is an entity's RoomCollection? Like view.Orders is customer.Orders ?
I'm not completely understanding what view.RoomCollection is bound to entity.Room means.
2) user adds two rooms to the view.RoomCollection
2*) during debug I check each room in the view.RoomCollection and all rooms seem to have an associated parent even the new ones which were just added
3) I run the segment of code from my last post attempting to associate any newly added rooms to the entity and I get the error
If view.RoomCollection == entity.RoomCollection, then any entity added to view.RoomCollection already have entity as associated entity.
Could you check that for me please?
You could try this: (not tested)
EntityCollection<RoomEntity> currentRooms = view.RoomCollection;
EntityCollection<RoomEntity> toProcess = new EntityCollection<RoomEntity>();
foreach(RoomEntity room in currentRooms)
{
if (entity.Room.IndexOf(room) < 0)
{
toProcess.Add(room);
}
}
entity.Room.AddRange(toProcess);
(clarification)
2*) during debug I check each room in the view.RoomCollection and all rooms seem to have an associated parent even the new ones which were just added - it seems that because the view.RoomCollection contains a list of RoomEntity which are associated with an entity, adding a new room to the collection is automatically associating the new room with the parent entity of all other rooms in the collection.
Correct. It's the same as: myCustomer.Orders.Add(myOrder); will under the hood do: myOrder.Customer = myCustomer;
Similarly, if you'd do: myOrder.Customer = myCustomer; then under the hood myCustomer.Orders.Add(myOrder);
is done. So if view.RoomCollection is a collection of an entity, you can better copy the entities over to a different collection: EntityCollection<RoomEntity> rooms = new EntityCollection<RoomEntity>(); rooms.AddRange(view.RoomCollection);
or use: view.RoomCollection.DefaultView.ToEntityCollection method.
When a room is added to a different entity's collection, the association with the previous parent is first removed, (which makes the room be removed from view.RoomCollection) and then room is added to entity.Room where it gets associated with entity.
This wouldn't be a problem if when I called save on the parent entity it noticed these newly related items but for some reason it doesn't. I would expect this to work the same way as insert where if any association exists between the target of the save and related entities those related entities would be saved too but this doesn't seem to be the case on update.
Hmm. so you have dirty, non-new entities in that room collection and these are not saved, though newly added entities are saved? Added to which collection exactly? (I find the collections a bit confusing, which one is the one you are using to store entities in just for the form and which one is the collection you're saving. )
Joined: 23-Jan-2006
I'll try working with a new EntityCollection<RoomEntity> and making a copy of everything in view.RoomCollection and see if that changes anything.
This wouldn't be a problem if when I called save on the parent entity it noticed these newly related items but for some reason it doesn't. I would expect this to work the same way as insert where if any association exists between the target of the save and related entities those related entities would be saved too but this doesn't seem to be the case on update.
Hmm. so you have dirty, non-new entities in that room collection and these are not saved, though newly added entities are saved? Added to which collection exactly? (I find the collections a bit confusing, which one is the one you are using to store entities in just for the form and which one is the collection you're saving. )
Maybe I didnt explain correctly. The dirty entities in view.RoomCollection which were already associated with the parent entity are being persisted properly on an update but any NEW entities added to the view.RoomCollection, although they are associated with the parent unit (when debugging and checking some newly added room in the RoomCollection, view.RoomCollection[0].IsNew == true && view.RoomCollection[0].Unit == entity) but still they are not persisted when I try to save the entity.
KastroNYC wrote:
I'll try working with a new EntityCollection<RoomEntity> and making a copy of everything in view.RoomCollection and see if that changes anything.
Ok, though it's key to understand that if you add an entity E to a collection which is contained in an entity E2 and E was already in another collection also contained in an entity, say E3, E is removed from E3's collection before it's added to E2's collection. THis makes foreach go crazy as you're enumerating over E3's collection.
This wouldn't be a problem if when I called save on the parent entity it noticed these newly related items but for some reason it doesn't. I would expect this to work the same way as insert where if any association exists between the target of the save and related entities those related entities would be saved too but this doesn't seem to be the case on update.
Hmm. so you have dirty, non-new entities in that room collection and these are not saved, though newly added entities are saved? Added to which collection exactly? (I find the collections a bit confusing, which one is the one you are using to store entities in just for the form and which one is the collection you're saving. )
Maybe I didnt explain correctly. The dirty entities in view.RoomCollection which were already associated with the parent entity are being persisted properly on an update but any NEW entities added to the view.RoomCollection, although they are associated with the parent unit (when debugging and checking some newly added room in the RoomCollection, view.RoomCollection[0].IsNew == true && view.RoomCollection[0].Unit == entity) but still they are not persisted when I try to save the entity. You save the view.Roomcollection ? Or the entity which is new?
If the entity is in the graph (and your debugging info suggests that, as view.RoomCollection[0].Unit is associated with an entity which is in the graph, namely entity) the entity should be saved if you save recursively. It's strange that it doesn't do that, because updates do work, so the graph traversal apparently does work, but it's important to know which entities are exactly saved and what the types are, how they relate to eachother.
If RoomCollection[0].Unit == entity then roomcollection[0] HAS TO be in entity.Room.
Joined: 23-Jan-2006
Ok, though it's key to understand that if you add an entity E to a collection which is contained in an entity E2 and E was already in another collection also contained in an entity, say E3, E is removed from E3's collection before it's added to E2's collection. THis makes foreach go crazy as you're enumerating over E3's collection.
I understand now so this is what i am seeing happen and its actual somewhat of a pain. I've been able to at least continue working on my project by insisting that when a new room be added to view.RoomCollection first i check for the presence of RoomCollection[currentItem].Unit and if its there I just save it and refetch if with full path. This has been working so for now this will do but I would like to make the code less chatty and preferablly in a way where the entity collections are more like a uow without the uow if that makes sense.
If RoomCollection[0].Unit == entity then roomcollection[0] HAS TO be in entity.Room
I understand this but trying to add it from the RoomCollection[0] to entity.Room seems to work and as you explain, actually removes it from RoomCollection in the process. So how can I traverse RoomCollection in a way that it would be aware of this?
Collections are the ones which know they're contained.
So what you could do is this: - in the view, use a NEW entity collection, and simply add the entities you want via either: - AddRange() or - entity.Room.DefaultView.ToEntityCollection. - you use the NEW collection inside your view. - then, after the view has been completed, you simply traverse it: - for every entity which is new, add it to the original collection, i.e. entity.Room. - every entity which isn't new, simply don't add it, as it's already there.
Though, what doesn't get to me is: why do you need all this if you WORK on entity.Room already? You modify that collection's entities and add new ones to that collection, so saving entity recursively will save them all.
Joined: 23-Jan-2006
That's actually my point exactly. When I check the view.RoomCollection as the rooms are added they are associated properly with their parent (so if x is the index of a new item, view.RoomCollection[x].Unit != null in debug returns true), but when I call Save on the entity (Unit) the edited items in the Room collection are updated appropriately as is the entities properties but the new rooms in the Room collection are not inserted. Why wouldn't these new items be inserted?
I'm lost, I can't follow up the "view" and "entity" scenario.
Would you please use simpler names for the sake of demonstration (try to use customer, order, orderdetails, products.... as a mapping names).
Also please post a complete code snippet, with the Saving part.
Thanks.