Rollbacking changes made to a list of Objects


We're currently evaluating Aurelius to know if it would fit our needs and it's doing pretty good so far.
We only struggle on one point : 

We have a property form which displays a list of items. There can be as many items in the list as the configuration needs. So we would be declaring a "TItem" with a [Entity] tag, that's all fine.
But we need to let the user modify this list (add/update/delete items) and finally cancel his changes if he's not satisfied.

How would you recommend us to do so?
We've thought about 3 ways for now:
  1. Use a TAureliusDataset, load it and make the changes on this dataset and then "Apply" the dataset or "discard" it.
    Pros : That should work and we can load the dataset with the Aurelius ObjectManager apparently. Which is good
    Cons : that's way less convenient than working with objects, and that's the whole point of an ORM right?

  2. Only let the user change the graphic items and then perform a "manual sync" between the GUI items and the content of the DB... hum
    Pros : none
    Cons : Risk of bugs, not evolutive etc...

  3. Use a transaction, save the TItem as the user modify them and commit the transaction if he applies his change. Rollback otherwise.
    Pros : pretty straightforward and easy
    Cons : We would have to deal with DB concurency, locks etc.. We're a cross DBMS app so that would be difficult to handle on 4 different DBMS (to be honnest that's why we want an ORM too, do the non DBMS-agnostic job for us)

Anything else comes to your mind?
Are we completely mis-understanding something? How does other people in the community implements such mechanisms?


I don't understand if your problem is mainly on the user interface, or object manipulation? Also using a transaction is not mutually exclusive with the other options. For user interface, the dataset is the best option because it does the binding with controls automatically. It has nothing to do with "not working with objects" because it's only for the binding (that's a misunderstanding most people do). The objects are still behind the dataset.

But for saving the objects in the database, if you need to save all-or-nothing, including inserts, updates, etc., then you must use the transaction, I don't see why it would not be agnostic? Why need locks? I think I'm a little confused with your exact needs.

Alright so you would recommend working with TAureliusDataset and Apply it afterwards.

That's fine to me for the cases where we'll be working with DBAware GUI components, it makes it dead simple. 
But what if we don't want/can to work with such components right now? We would have to implement the "synchronisation" mechanism between the control and the dataset ourselves right? -> writing in the dataset through .FieldByName('name') := val

You said that the "objects are still behind the dataset", I guess you're refering to TAureliusDataset's .intenalList ( ) but those are read-only right? We wouldn't be able to manipulate the objects in this list to see the dataset automatically updated?

Now as you said it we can still use Transactions at the end of the process (when applying changes) i agree.

>>>Alright so you would recommend working with TAureliusDataset and Apply it afterwards.

Only for GUI binding, not for operations. I said I didn't understand well what you need.
If you want to present data in a Delphi form and don't want to use Aurelius Datatset, then you have to manually read data from objects and set in your visual controls. Or use live bindings.

If you use SetSourceList to provide the list used by the aurelius dataset, it will automatically add/remove items from that list when you Insert/Delete records to/from dataset.

Actually what I want is pretty much what was asked before here  :

You said in that post you were considering adding a function to do this without the object manager change trick. What's up with that?
Destroying the ObjectManager and creating a new one and merging the objects into it might do the job for now though

Have you checked the new Refresh method? It allows you to rollback the object to its original state, thus changes made to that object will be discarded.

That would work at an object-level but wouldn't when considering a list.

I'd need something that makes it possible to the user to DELETE an object (or ADD or UPDATE) and then rollback this delete if he wants to.

Not sure what you mean? Do you have a specific example?

Ok let's assume the following situation : 

The class/entity :


TItem = class
    FId : Integer;
    FItemName : String;

What I would like is to retrieve all TItems from DB. 
ObjectManager.findAll should do just fine : .

What i would like then is give my user the opportunity to DELETE a TItem when he wants to. 
"I don't want this item in my database anymore"
ObjectManager.Remove is ok for this specific purpose :

But the thing is once you removed an TItem with ObjectManager.remove, you cannot rollback this delete.
So if the user sees he made a mistake he can't "cancel" his action. It's done for good and forever.
"oops maybe i shouldn't have removed this object, let's click the cancel button"
Therefore I cannot use .Remove if I want to offer the user the opportunity to "cancel" his actions on the objects list.

.Refresh doesn't fit because once the object is gone, it's gone, you can't "refresh" it to "make it come back again"

I hope i'm being clear.

But I don't see how extracting an object from the manager would help in this case?

This is the same case of the regular TDataset. If you delete a record, it's gone. You must either:

1. Do not delete/remove the object until the user confirm the changes. If you want to rollback things, why are you effectively removing it?
2. Use transactions and then rollback if user cancels it. After the rollback you need to perform the query again, as you would do with a TDataset.Refresh.