Reflecting entities removed from collections as deleted in the db

Posts   
 
    
BlackMamba avatar
BlackMamba
User
Posts: 34
Joined: 30-Apr-2004
# Posted on: 21-Apr-2005 19:34:51   

Hello, I have this problem that is quite frustrating at times, but maybe it's because of my habit with another framework I'm used to. Basically what I was expecting was too see something like this:


Dim group as GroupEntity
..... fetch code here

group.Children.Remove(0)
group.Children(1).GrandChildren.Remove(0)

adapter.SaveEntity(group) 


The code above (I omitted the recursive save parameter), in my mind, should result in LLBLGen code deleting 2 records. This does not happen and Frans explained that the only way to do it is using UnitOfWork classes. But, I feel this should be there and would like opinions on this.

For example, in our old vb6 framework, binding an entity with it's related collections to a master-detail form was very easy. When a record was deleted from a detail (a detail grid for example), it would be 'logically deleted' meaning that if the master record was updated, all items in the deleted collection would be deleted from the db first, the new ones added and modified ones updated. All this was handled by the master 'entity'.

With LLBLGen this apparently simple task is made complex. I feel that UnitOfWork, even though it will do the job, gets in the way of a normal Save operation.

Perhaps this is the border line where smarter objects wrapping of LLBLGen code should come into play?

Cheers

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39861
Joined: 17-Aug-2003
# Posted on: 21-Apr-2005 20:13:12   

You should use a unitofwork for this, as save is saving changes in entities, not deleting entities. It might seem weird at first, but it's more natural. For example, you remove an entity from a collection in your example and then save the parent entity. Imagine that I'd do that to just remove the entity from the in-memory collection simple_smile . I then suddenly will experience my entity being removed from the database as well! simple_smile

Frans Bouma | Lead developer LLBLGen Pro
psandler
User
Posts: 540
Joined: 22-Feb-2005
# Posted on: 21-Apr-2005 20:15:10   

BlackMamba wrote:

The code above (I omitted the recursive save parameter), in my mind, should result in LLBLGen code deleting 2 records. This does not happen and Frans explained that the only way to do it is using UnitOfWork classes. But, I feel this should be there and would like opinions on this.

[...]

With LLBLGen this apparently simple task is made complex. I feel that UnitOfWork, even though it will do the job, gets in the way of a normal Save operation.

Perhaps this is the border line where smarter objects wrapping of LLBLGen code should come into play?

Cheers

You shouldn't need unit of work to delete entities from a collection. You could simply use a separate entitycollection for deletes.

Consider this pseudocode, since I don't have access to a code editor at the moment (I also don't know VB.Net very well simple_smile ):


Dim group as GroupEntity
..... fetch code here
Dim deleteCollection as New EntityCollection()

deleteCollection.Add(group.Children(0))
group.Children.Remove(0)
group.Children(1).GrandChildren.Remove(0)

adapter.SaveEntity(group) 
adapter.DeleteEntityCollection(deleteCollection)


The entity collection for deletes doesn't even require that all the entities be of the same type.

psandler
User
Posts: 540
Joined: 22-Feb-2005
# Posted on: 21-Apr-2005 20:19:49   

In the above code, I neglected to delete the grandchild:

Dim group as GroupEntity
..... fetch code here
Dim deleteCollection as New EntityCollection()

'added:
deleteCollection.Add(group.Children(1).Grandchildren(0))
deleteCollection.Add(group.Children(0))

group.Children.Remove(0)
group.Children(1).GrandChildren.Remove(0)

adapter.SaveEntity(group) 
adapter.DeleteEntityCollection(deleteCollection)
BlackMamba avatar
BlackMamba
User
Posts: 34
Joined: 30-Apr-2004
# Posted on: 21-Apr-2005 20:41:37   

Otis wrote:

You should use a unitofwork for this, as save is saving changes in entities, not deleting entities. It might seem weird at first, but it's more natural. For example, you remove an entity from a collection in your example and then save the parent entity. Imagine that I'd do that to just remove the entity from the in-memory collection simple_smile . I then suddenly will experience my entity being removed from the database as well! simple_smile

Yes what you say is true but then I feel that since we're using an object relational mapper, then there must be a way to map the removal of an entity from a collection to the persistence layer since adding one to the collection will result in adding a corresponding record in the db. That's why in our old framework we had a Remove method and a LogicalRemove method. The first one would remove and that's it, the second one would remember to delete from the db as well.

Anyhow, thanks for your opinions.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39861
Joined: 17-Aug-2003
# Posted on: 22-Apr-2005 10:50:35   

BlackMamba wrote:

Otis wrote:

You should use a unitofwork for this, as save is saving changes in entities, not deleting entities. It might seem weird at first, but it's more natural. For example, you remove an entity from a collection in your example and then save the parent entity. Imagine that I'd do that to just remove the entity from the in-memory collection simple_smile . I then suddenly will experience my entity being removed from the database as well! simple_smile

Yes what you say is true but then I feel that since we're using an object relational mapper, then there must be a way to map the removal of an entity from a collection to the persistence layer since adding one to the collection will result in adding a corresponding record in the db. That's why in our old framework we had a Remove method and a LogicalRemove method. The first one would remove and that's it, the second one would remember to delete from the db as well.

You have a point, but you can also see the collections in an entity as the result of a filtered view on the set of related entities and see them as such and not as part of the entity they're contained in.

For example, if I fetch a customer and its last 10 orders, if I remove one order from that list, you could say, it's removed from the filtered view on the total set of orders for that customer.

The reason why this ambiguity is not implemented in code is that deletes aren't reversable. A bad update can be undone by setting the data again to the right values, but a delete (perhaps a whole graph!) is much harder to track back, especially if the user didnt intent do delete anything, just removing a row from the collection.

I know it's an ambiguity and I know it depends on which way you look at things to understand the way it is now and I also understand your point and in fact I do think you have a point and are right, but there is a downside to that position, which is why up till now haven't proceeded with implementing it. The same goes for cascading deletes.

The unitofwork is there to collect work to be done on the entities in question, which can help you with scheduling the deletes you want to perform.

Frans Bouma | Lead developer LLBLGen Pro
BlackMamba avatar
BlackMamba
User
Posts: 34
Joined: 30-Apr-2004
# Posted on: 22-Apr-2005 11:44:42   

Otis wrote:

BlackMamba wrote:

Otis wrote:

You should use a unitofwork for this, as save is saving changes in entities, not deleting entities. It might seem weird at first, but it's more natural. For example, you remove an entity from a collection in your example and then save the parent entity. Imagine that I'd do that to just remove the entity from the in-memory collection simple_smile . I then suddenly will experience my entity being removed from the database as well! simple_smile

Yes what you say is true but then I feel that since we're using an object relational mapper, then there must be a way to map the removal of an entity from a collection to the persistence layer since adding one to the collection will result in adding a corresponding record in the db. That's why in our old framework we had a Remove method and a LogicalRemove method. The first one would remove and that's it, the second one would remember to delete from the db as well.

You have a point, but you can also see the collections in an entity as the result of a filtered view on the set of related entities and see them as such and not as part of the entity they're contained in.

For example, if I fetch a customer and its last 10 orders, if I remove one order from that list, you could say, it's removed from the filtered view on the total set of orders for that customer.

The reason why this ambiguity is not implemented in code is that deletes aren't reversable. A bad update can be undone by setting the data again to the right values, but a delete (perhaps a whole graph!) is much harder to track back, especially if the user didnt intent do delete anything, just removing a row from the collection.

I know it's an ambiguity and I know it depends on which way you look at things to understand the way it is now and I also understand your point and in fact I do think you have a point and are right, but there is a downside to that position, which is why up till now haven't proceeded with implementing it. The same goes for cascading deletes.

The unitofwork is there to collect work to be done on the entities in question, which can help you with scheduling the deletes you want to perform.

I see your points. Perhaps you could provide a way to explicitly tell LLBL code that you want an entity deleted from the db as well. So by default it will be removed from the collection and that's it, keeping the behaviour like it is now, but when needed it could be added to an internal 'toDelete' collection and actually get deleted during a recursive Save. Anyways, I know it's a delicate subject and I guess it must be very clear and robust behaviour if you're going to implement it.

For now thanks and I will go on and use the unitofwork.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39861
Joined: 17-Aug-2003
# Posted on: 22-Apr-2005 12:17:21   

That's also crossed my mind, some sort of setting. I'll see if I can build that in into a future version.

btw, during a recursive save, you work from pk down to fk in the tree, recursive deletes work from the lowest fk leave up to the highest pk leave wink . So it will be 2 distinct actions anyway. But of course for the user that's hidden.

Frans Bouma | Lead developer LLBLGen Pro
Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 11-Sep-2005 16:16:55   

Sorry for the late suggestion. Instead of using a "toDelete internal collection", why don't we use the same analogy as IsNew to differentiate between Updates and Inserts, and have a new attribute "toDelete" inside the Entity classes, which would be first checked on save functions?

This would be a nice alternative to delete items in a collection.

What makes this valuable to me is that we are using a Web Service and the web application has a Grid built from an Entity Collection and we wants to Have Inserts, updates and Deletes to be functional with only one function call to the Web Service.

I know that The Unit of Work Already performs this task, but I think having one Entity Collection enclosed in the XML sent, is slimmer to use.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39861
Joined: 17-Aug-2003
# Posted on: 12-Sep-2005 10:12:02   

I'll consider it for v2.0.

In the meantime, the UoW is the way to go, even if it's bringing more data to the XML message.

Frans Bouma | Lead developer LLBLGen Pro