Confused with Update and Flush

I am very confused with Save, SaveorUpdate, Update and Flush.

I've read the manual but I am not sure I understand things well.

Should I call Save and then Flush? Can I do Update and then Flush.

The thing is that Update and then Flush works in one instance in my app but raises an exception in another and I can't figure out why. The object manager is the same in both cases.

or can I change an entity retrieved from the database and just call Flush without Update?




Flush is needed to modify objects. So you need to call Flush after Update.
Save doesn't need Flush, once you call Save, data is inserted in the database.
But Update is indeed not needed. If you retrieved an entity from the database, it's already in the manager. All you need to do is modify its properties and call Flush, changes will be persisted.

Update is only needed when you have an instance that is not in the manager, so you use Update to put that instance in the manager.

Thanks Wagner. 

Say I have a class with a field that points to another class.

If I save for the first time, if the second class is nil it doesn't create the record in that table.
If I retrieve the class and create the second class, do I call Flash again or I have to save the second class first and then do flush?

Depends on the cascade type you set for each association. If you define to cascade save/update (default), then Flush will automatically save the second class for you, if needed.

Thanks Wagner. I see now how it works.

Hi Wagner,

I retrieve a user list like this: 


now I want to keep the first entry and I do this:

fCurrentUser:=Users.items[0]; //I check it's not empty

and now I have the user record in the fCurrentUser correctly.

Now, when I want to update it in the database, I do the following:

I create a new object manager and then:
....update fCurrentUser.....
tmpObj.Flush <-- this gives access violation. If I remove it the changes are not saved.

I even tried to merge fCurrentUser to a new record:
newUser: =tmpObj.Merge<Tusers>(fCurrentUser);

but it doesn't save the updates.

I've also tried the SaveOrUpdate.

How should I deal with this? Am I managing the first part (to keep the result) correctly?




I forgot to mention that I tried 
tmpObj.Evicit(fcurrentuser) instead of ownobject

but without luck.

Hi John, your understanding of how it works is mostly correct. If you have an object "outside" the manager, you can use Update/Flush to apply changes, or you can use Merge/Flush to apply the changes. (you don't need to call Update after Merge). The difference between both is that the former will add the object itself to the manager, and the latter will load the object in the manager and copy data in the "outside" object to the "inside" object.

So code is mostly correct, the problem you are having is due anything else that is not visible in your post. Also, you should use Evict instead of using that approach with OwnsObjects (which is not good because the other objects in the list will not be destroyed and thus leaked).

You have to check the object tree (associations) and see if you have cascades applied for all of them. For example, if you evict current user, but that user has an association, make sure there is evict cascade on it as well.

Thanks, Wagner. I'll check the code again.

Can I use SaveOrUpdate instead or merge/update? I guess I don't need to call Flush after this, right?

SaveOrUpdate just checks if the object has an id. If it does, it calls Update. If not, it calls Save. 

You will still need to call Flush if it does an Update, for example. 

Ok, Wagner I figured out what the problem is. I've got this TBolb field:

    [Column('Picture', [TColumnProp.Lazy])]
    FPicture: TBlob;

1. Shouldn't that be Nullable? The "Not Null" is unchecked in DM

2. When you evicit an object, what happens to the Lazy association? Once you attach the object to the manager, can it find the association?

I removed the Blob field and now the database updates correctly.

  1. TBlob is always nullable

    2. Indeed, the TBlob remains unloaded. If you try to access it, it will reference the old TObjectManager to load it. If that manager is gone, an error will happen. The work around is to keep the original TObjectManager alive or force the blob load before evicting.