UnitOfWork and DefaultOrder

Posts   
 
    
kievBug
User
Posts: 105
Joined: 09-Jan-2009
# Posted on: 10-Jan-2011 17:49:04   

Hey guys,

We are currently on 2.6.10.0930 build.

I'm using UnitOfWork2 class and setting default commit order as following: UnitOfWorkBlockType.Updates, UnitOfWorkBlockType.UpdatesPerformedDirectly, UnitOfWorkBlockType.Deletes, UnitOfWorkBlockType.DeletesPerformedDirectly, UnitOfWorkBlockType.Inserts,

After I do:

TestEntity test = {loaded existing entity}; test.Related = new RelatedEntity() { set fields here };

and add test to unit of work, it throws Fk exception, because it updates TestEntity before it inserts related entity. Which is not a correct behavior as for me.

As for me entity should correctly be saved in this case - insert of the related should go before the update because of the dependencies. And update sequence should be used only when the sequance is not clear from the dependencies or there is a conflict, or something like this.

why the sequence is like this: 1. Updates vs Deletes - updates should go before deletes because of the possible references to entities that are being deleted. So I first will set the reference to null and after that will will delete related.

  1. Updates, Deletes vs Inserts - update/deletes should go before insert because of unique indexes on the table i.e. if table has unique index and uow has updates(or deletes) and inserts than updates/deletes should go before the insert.

Anton

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 11-Jan-2011 05:56:15   

Hi Anton, this is copied from documentation:

Specifying the order in which the actions are executed The UnitOfWork2 class typically executes the actions added to it in the following order: CallBacks for the PreEntityInsert slot, Inserts, CallBacks for the PreEntityUpdate slot, Updates, UpdateEntitiesDirectly calls, CallBacks for the PreEntityDelete slot, Deletes, CallBacks for the PostEntityDelete slot, DeleteEntitiesDirectly calls. This order can be too limited, for example if you first have to delete an entity before a new insert can take place because the entity to insert has the same value for a field with a unique constraint. LLBLGen Pro lets you define entity oriented actions to be ordered in a different order, so the UnitOfWork2 class will for example first execute the deletes and then the updates. This is done by specifying a list of UnitOfWorkBlockType values for the property unitOfWork2.CommitOrder. By default you don't have to specify any commit order, the UnitOfWork2 class will follow the sequence as specified above. However as soon as you specify a list of UnitOfWorkBlockType values for CommitOrder, it will use that list instead. This means that if you omit a block type, these actions aren't executed at all. Duplicates are filtered out so specifying a blocktype twice has no effect, the second one is ignored.

So if that ordering doesn't fit to you, you can change it. If I understood well, you changed the order but now you receive the exception. Well that is expected due to the fk restriction (you must insert the related first and then update the entity). So maybe your ordering doesn't fit to you.

kievBug wrote:

As for me entity should correctly be saved in this case - insert of the related should go before the update because of the dependencies. And update sequence should be used only when the sequance is not clear from the dependencies or there is a conflict, or something like this.

why the sequence is like this: 1. Updates vs Deletes - updates should go before deletes because of the possible references to entities that are being deleted. So I first will set the reference to null and after that will will delete related.

  1. Updates, Deletes vs Inserts - update/deletes should go before insert because of unique indexes on the table i.e. if table has unique index and uow has updates(or deletes) and inserts than updates/deletes should go before the insert.

I don't follow you on your arguments about your commit ordering. Anyway you cant use that ordering (your custom), if you encounter constraints you could break that in two unitOfWork objects. Does that makes sense to you?

David Elizondo | LLBLGen Support Team
kievBug
User
Posts: 105
Joined: 09-Jan-2009
# Posted on: 11-Jan-2011 07:15:50   

Well, the default order won't work either in this case.

The thing is I do not want to specify this order at all and I want it to be more intelligent than it is now.

As I understand the whole point of the unit of work is to group changes, and handle those as a batch. But the problem is that it is not possible to do that because when I use it, it actually changes the standard behavior of saving an entity i.e. using dependencies to determine the sequence of saving entity graph.

So this basically mean that in general case, UnitOfWork is useless and developer will need to come up with something to determine the sequance of saving the changes - which is definately not good. In specific cases, where everything is hardcoded and developer knows the sequance(and configures it by passing as an argument to the constructor) it works fine, but not in generic case.

It is a bit strange to me why dependency graph is used in one case, and ignored in the other.

Thanks, Anton

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 11-Jan-2011 09:49:26   

Well, the default order won't work either in this case.

How come it won't work, the default order is Insert, Update then delete. So as far as I know, it should work in your case.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 11-Jan-2011 12:52:05   

kievBug wrote:

Well, the default order won't work either in this case.

The thing is I do not want to specify this order at all and I want it to be more intelligent than it is now.

As I understand the whole point of the unit of work is to group changes, and handle those as a batch. But the problem is that it is not possible to do that because when I use it, it actually changes the standard behavior of saving an entity i.e. using dependencies to determine the sequence of saving entity graph.

So this basically mean that in general case, UnitOfWork is useless and developer will need to come up with something to determine the sequance of saving the changes - which is definately not good. In specific cases, where everything is hardcoded and developer knows the sequance(and configures it by passing as an argument to the constructor) it works fine, but not in generic case.

It is a bit strange to me why dependency graph is used in one case, and ignored in the other.

Thanks, Anton

Looking at your startpost, I don't understand what you're doing: you set the order to do updates first, before inserts, and then when you commit, you say it should inserts first. But, you specified it to do updates first, so of course it does updates first wink .

The default is inserts -> updates -> deletes. Per group, it sorts the entities participating using a topological sorting algorithm, which has as result a list in which all entities are ordered in such a way that every entity X done before entity Y doesn't depend on Y, so no errors occur.

The action queues (which entities to insert, update and delete) are calculated in 1 go, and then performed in the order you specified. So if you added an entity 'test' which exists already, and it relies on an entity 'Y' which has to be inserted first, make sure 'test' references Y. You also have to make sure the commit order is set (e.g. stick to the default!) in such a way that you won't run into problems.

Example: Customer, Order. When I want to add a new Order instance myOrder to the database, and it is for an existing Customer myCustomer, I simply do: myOrder.Customer = myCustomer; unitOfWork.AddForSave(myOrder); unitOfWork.Commit(adapter, true);

that's it. If myCustomer is new, it will save myCustomer first. If it wasn't new, it will save myOrder first, and update myCustomer afterwards.

So I'm confused what exactly you want to do that doesn't work with the default. The situations where the default order isn't ideal is when you want to delete an existing entity and re-insert it. That's about the only reason.

For example, if I have the order and it was booked under the wrong customer, which has to be deleted, I do: myOrder.Customer = rightCustomer; // will dereference the original customer unitOfWork.AddForSave(myOrder); unitOfWork.AddForDelete(myCustomer); unitOfWork.Commit(adapter, true);

-> will save myOrder as an update -> will delete myCustomer.

Frans Bouma | Lead developer LLBLGen Pro
kievBug
User
Posts: 105
Joined: 09-Jan-2009
# Posted on: 11-Jan-2011 15:01:51   

Ok, I see your point.

Let me check it one more time, it seems that I'm doing something wrong.

Thanks, Anton