Remove and Delete entities in a collection

Posts   
 
    
slnsalim
User
Posts: 10
Joined: 12-Jan-2004
# Posted on: 05-Feb-2004 16:06:28   

Hi

I have a grid bound to a Collection entity. Each row in my grid has a DELETE button. I would like to repeatedly add and remove entities for the collection and only commit the changes to the database when I click on the SAVE button. Since I have removed the entities from the collection, I can't iterate through the collection to delete them. So I tried setting the EntityState to Deleted for the entities I want to delete but an exception is thrown when I iterate the collection and try to actually Delete them.

Is there some other property I can get /set that will still let me iterate through a collection and Save or Delete entities as appropriate, or is there some other clever way I have not yet discovered?

Cheers Sarina

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 05-Feb-2004 16:36:34   

You could create an empty entity collection of the type you also bind to the grid and when you delete an entity from the grid, place it in that collection. WHen the user presses 'save') you can simply call DeleteMulti() on that collection you stored the removed entities in to delete them in 1 transaction.

Frans Bouma | Lead developer LLBLGen Pro
slnsalim
User
Posts: 10
Joined: 12-Jan-2004
# Posted on: 05-Feb-2004 16:50:34   

I had thought about it and hoped to avoid it. But if there is no other way.... disappointed

Thanks, as ever, for such a speedy reply

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 05-Feb-2004 17:38:28   

slnsalim wrote:

I had thought about it and hoped to avoid it. But if there is no other way.... disappointed

The reason the entity is not deleted from the persistent storage when you remove it from the collection is because it's unclear for the code what you want: you just want to remove it from the collection, you want to remove it from the binded collection or you want to remove it from the database completely? Or do you want to set a 'deleted' field to true?

I decided I can't make that decision for the developer, especially because it is about deletes, which are irreversable.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 07-Feb-2004 16:24:43   

I forgot to mention: the collection classes have an event: BeforeRemove. This event is fired when Remove() or RemoveAt() is called. 'sender' object in the event is the entity object being removed. Perhaps this will ease your development a bit.

Frans Bouma | Lead developer LLBLGen Pro
jeffkararo
User
Posts: 76
Joined: 06-Jan-2004
# Posted on: 25-Mar-2004 16:52:16   

So if I call RemoveAt() on the collection and then call SaveMulti(), the collection will not delete the record from the DB?

Wasn't this how it worked in version 2003.1?

Thanks

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 25-Mar-2004 17:47:32   

jeffkararo wrote:

So if I call RemoveAt() on the collection and then call SaveMulti(), the collection will not delete the record from the DB?

True, it will only remove it from the collection. The reason for this is that a collection doesn't have to contain all the entities: it is just a subset of entities based on a set of rules (the filters used to fetch them). Removing an entity from that set can mean: remove this entity from the db, OR it can mean: remove this entity from the set of entities matching some rule, because now I use this set of entities in another context.

Wasn't this how it worked in version 2003.1? Thanks

No, it has never been that way simple_smile

Frans Bouma | Lead developer LLBLGen Pro
wojo
User
Posts: 69
Joined: 10-Mar-2004
# Posted on: 15-Apr-2004 20:31:37   

Hmm, is it possible to have both the current Remove() behavior where entries are just removed from the collection in addition to a new Delete() method which would mark entities for deletion from the database? It would be the best of both worlds, no?

I implemented this myself using a derived EntityCollection with Delete(IEntity2) and DeleteAt(int) methods which keep track of deleted entities in an ArrayList. OnInsert was also overridden to remove inserted entities from the removed list if they happened to exist in there already. I then created an overridden DataAccessAdapter.OnSaveEntityCollection() which removes the entities before calling the base method.

It would be nice if this functionality was built into LLBLGen, though. Right now I have to play a bunch of tricks to create my derived EntityCollection and cast them out of entities so I can access the added delete methods, etc.

Opinions?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 15-Apr-2004 21:55:15   

wojo wrote:

Hmm, is it possible to have both the current Remove() behavior where entries are just removed from the collection in addition to a new Delete() method which would mark entities for deletion from the database? It would be the best of both worlds, no?

I implemented this myself using a derived EntityCollection with Delete(IEntity2) and DeleteAt(int) methods which keep track of deleted entities in an ArrayList. OnInsert was also overridden to remove inserted entities from the removed list if they happened to exist in there already. I then created an overridden DataAccessAdapter.OnSaveEntityCollection() which removes the entities before calling the base method.

It would be nice if this functionality was built into LLBLGen, though. Right now I have to play a bunch of tricks to create my derived EntityCollection and cast them out of entities so I can access the added delete methods, etc.

Opinions?

I don't think it is wise to add this, as it will add to confusion as I've explained earlier. Normally, a little confusion is not that bad, people should read some docs once in a while wink but delete is such a drastic action I don't think it is wise to opt for a confusing option.

What you can do is add removed entities to a new EntityCollection and delete them in one transaction using DeleteEntityCollection().

Frans Bouma | Lead developer LLBLGen Pro
Kovan
User
Posts: 19
Joined: 26-Sep-2005
# Posted on: 25-Oct-2005 19:04:57   

There should be a new method called MarkForDeletion and that will take care of this problem for those of us who find this to be a essential method/property

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 25-Oct-2005 21:16:59   

Kovan wrote:

There should be a new method called MarkForDeletion and that will take care of this problem for those of us who find this to be a essential method/property

I'll add it to the todolist for 2.0. Thanks for the suggestion. simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Sokon1
User
Posts: 97
Joined: 17-Jul-2006
# Posted on: 30-Mar-2007 11:20:20   

Otis wrote:

Kovan wrote:

There should be a new method called MarkForDeletion and that will take care of this problem for those of us who find this to be a essential method/property

I'll add it to the todolist for 2.0. Thanks for the suggestion. simple_smile

Hi,

What has become of this? I ran into this problem the other day and I searched this forum for hints to get rid of this problem. I can't believe the only approach is to use a Unit of Work. Since the entity properties "IsNew" and "IsDirty" flag if there must be a "INSERT" or a "UPDATE" I would have thought there is a "IsDeleted" flag which marks an entity in a collection as "deleted" and that it will be deleted from the DB the next time I call collection.Save().

Seems to me a similiar approach as described above. Because I use v2.0 of LLBLGen I wondered where this feature might be. wink Please help me find it! Thanks in advance!

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 30-Mar-2007 11:39:20   

It was postponed till v2.1. In v2.1 we'll add a feature where you can attach a Unitofwork to a collection and let that track deletes.

Frans Bouma | Lead developer LLBLGen Pro
Sokon1
User
Posts: 97
Joined: 17-Jul-2006
# Posted on: 30-Mar-2007 12:51:07   

Otis wrote:

It was postponed till v2.1. In v2.1 we'll add a feature where you can attach a Unitofwork to a collection and let that track deletes.

Oh great! The roadmap predicts end of Q1 2007 for v2.1, you mean next week I can use it? Not bad... wink

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 30-Mar-2007 13:37:11   

Heh, you're funny simple_smile

Seriously: we hope to have the v2.1 beta at the end of April

Frans Bouma | Lead developer LLBLGen Pro
sparq
User
Posts: 63
Joined: 14-Mar-2010
# Posted on: 16-Mar-2017 22:25:44   

Otis wrote:

Heh, you're funny simple_smile

Seriously: we hope to have the v2.1 beta at the end of April

What happened? 10 years later I'm running into this problem again using 2.6.

The following code results in no deletion of child records from the DB;


var p = new ParentEntity(1234);
p.Children.Clear();
p.Save(true);

And I can't see any "MarkForDeletion" or "IsDeleted" properties.. I want to have the deletes performed within the same transaction as the parent entity Save() call without adding a lot of boiler-plate code to create a transaction manually, add all related entities to that transaction, etc, etc.

Surely there is a solution to this problem now?

I've also tried:


var p = new ParentEntity(1234);
p.Children.RemovedEntitiesTracker = new ChildCollection();
foreach(var c in p.Children.ToArray())
{
    c.FlagMeAsChanged(); // all these calls on the child entity seem fruitless
    c.IsDirty = true;
    c.Fields.State = EntityState.Deleted;
    c.Fields.IsDirty = true;
    p.Children.Remove(c);
}
// at this point the RemovedEntitiesTracker collection is full and p.Children.Count is 0
p.Save(true);

I have managed to delete records using UnitOfWork but that's unacceptable having to traverse the object tree yourself, manage sorting out saves and deletes, handling transactions, etc - you may as well not have an ORM.

Thanks, Ben

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 17-Mar-2017 07:23:43   

Removing entities from a related collection is ambiguous, so you have to handle it.

If you perform the remove action in code, then you know what to track.

And the removed entities are placed in that collection. If you have a big graph, then maybe you can use a generic collection where you add to it all entities in those RemovedEntitiesTracker collection and issue the delete action in one go.

In all cases the same logic has to be done somewhere.

sparq
User
Posts: 63
Joined: 14-Mar-2010
# Posted on: 19-Mar-2017 21:30:36   

Walaa wrote:

Removing entities from a related collection is ambiguous, so you have to handle it.

Understood - What I'm looking for is the best way to handle it.

Walaa wrote:

If you perform the remove action in code, then you know what to track.

And the removed entities are placed in that collection. If you have a big graph, then maybe you can use a generic collection where you add to it all entities in those RemovedEntitiesTracker collection and issue the delete action in one go.

In all cases the same logic has to be done somewhere.

How would you suggest using the RemovedEntitiesTracker could help?

I have multiple object trees many levels deep and want to save recursively from the root object in a single transaction, so when I save the root entity some grandchildren I removed should be deleted.

Is there a built in way to search the tree for any removed entity trackers?

Does 5.1 address this problem?

FYI.. I have resolved this by adding a "Root Entity" property to CommonEntityBase along with a collection of entities to delete and a recursive save method that uses a UnitOfWork to perform the save and deletes at the same time.

The obvious problem with this is that I need to remember to override that root entity property on every entity that is part of an object tree which will no doubt be forgotten in some cases leading to user deletes being missed.

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 20-Mar-2017 05:57:09   

[quotenick="sparq"]

Walaa wrote:

How would you suggest using the RemovedEntitiesTracker could help?

The following example is taken from the documentation (Tracking entity remove actions):

// First fetch all customers from Germany with their orders. 
EntityCollection<CustomerEntity> customers = new EntityCollection<CustomerEntity>();
PrefetchPath2 path = new PrefetchPath2(EntityType.CustomerEntity);
path.Add(CustomerEntity.PrefetchPathOrders);
using(DataAccessAdapter adapter = new DataAccessAdapter())
{
    adapter.FetchEntityCollection(customers, 
        new RelationPredicateBucket(CustomerFields.Country == "Germany"), 
        path);
}

// we now will add a tracker collection to the orders collection of customer 0.
EntityCollection<OrderEntity> tracker = new EntityCollection<OrderEntity>();
customers[0].Orders.RemovedEntitiesTracker = tracker;

// after this, we can do this:
customers[0].Orders.Remove(myOrder);

// and myOrder is removed from the in-memory collection customers[0].Orders
// and it's placed in 'tracker'. We can now delete the entities in tracker
// by using a UnitOfWork2 object or by calling adapter.DeleteEntityCollection(tracker).

sparq wrote:

I have multiple object trees many levels deep and want to save recursively from the root object in a single transaction, so when I save the root entity some grandchildren I removed should be deleted.

Is there a built in way to search the tree for any removed entity trackers?

You could traverse the tree so inspect for collections that have the RemovedEntitiesTracker property set.

sparq wrote:

The obvious problem with this is that I need to remember to override that root entity property on every entity that is part of an object tree which will no doubt be forgotten in some cases leading to user deletes being missed.

Yes, you would have the same problem in other options, like the RemovedEntitiesTrackers: the programmer have to set it and use it accordingly.

David Elizondo | LLBLGen Support Team
sparq
User
Posts: 63
Joined: 14-Mar-2010
# Posted on: 20-Mar-2017 21:29:50   

daelmo wrote:

You could traverse the tree so inspect for collections that have the RemovedEntitiesTracker property set.

Yes but the question is: is there an easy built-in way to do this without coding everything by hand? Obviously LLBLGen can walk the tree already because it can perform recursive saves - but is this functionality available to the user?

daelmo wrote:

Yes, you would have the same problem in other options, like the RemovedEntitiesTrackers: the programmer have to set it and use it accordingly.

Is there a way of solving this problem in 5.1?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 20-Mar-2017 22:13:51   

It is in a way, through datascopes. See: http://www.llblgen.com/Documentation/5.1/LLBLGen%20Pro%20RTF/Using%20the%20generated%20code/gencode_datascopes.htm.

They can manage addition of removal tracker collections and collect the work to be done in a unit of work, so it's easier to get everything together. Mainly useful for UIs. Not sure if that's your use case.

Frans Bouma | Lead developer LLBLGen Pro
sparq
User
Posts: 63
Joined: 14-Mar-2010
# Posted on: 20-Mar-2017 22:18:56   

Otis wrote:

It is in a way, through datascopes. See: http://www.llblgen.com/Documentation/5.1/LLBLGen%20Pro%20RTF/Using%20the%20generated%20code/gencode_datascopes.htm.

They can manage addition of removal tracker collections and collect the work to be done in a unit of work, so it's easier to get everything together. Mainly useful for UIs. Not sure if that's your use case.

Yes, sorry the use case is a WinForms UI where a user will load a large object tree, mess with it, then either persist the whole tree at once or discard it.

I'll check out datascopes