Aurelius Dataset

Using the dataset, I can edit rows and insert rows. When a Manager is attached, persisiting to the database ist done by the Manager. However, if I need more Control e.g. I want to use a Transaction, I am unsure how to preoceed.

If I have modified more than one object/Entity, I can use Flush to persist this in the database. Unfortunately flush does not handle new entities, thus no INSERT to the database.

How do I detect the rows in the dataset, that must be SAVEd?

Can I use the ID for this?

tx Bernd

Using the dataset you have the OnObjectInsert event that is fired whenever the record is Post and a new object should be saved. You can then save your object from there. If it's inside a transaction, there should be no problem in saving it, since all changes will only be committed when you call Commit. Even then, alternatively you can just save the object instance in some temporary list and then when you want, you just call Save for all those objects in that list.

So transactions are nothing doing with the database? They just withhold the actual INSERT/UPDATE/DELETE?


So I could start a transaction, assign the manager to the dataset, and when finished I do a commit?

BTW: Tx for your answer on a saturday! I appreciate that!

Well, keep in mind that "transactions" are just database transactions. Aurelius does nothing in that area besides just starting the transaction in the database. It will still perform the INSERT statement when you call Save, but of course since it's a database transaction, it won't persist changes until you commit.


In other words, it's out of scope of Aurelius, it's a database thing. 

You're welcome!

Never leave the COMMIT to the user. 


Encapsulating user interaction with BeginTransaction/Commit is not a good idea. If the user leaves the PC, the transaction might block the database.

I used to work with ClientDataSets as a replacement for cached updates and I think, I look at Aurelius the same way:
- let the user edit
- start trans
- write to db
- commit

But I am stuck on how to correctly bind the FNCGrid thru the dataset to the objects. I sent you a demo that shows where I am having problems.

tx for your perfect support!

You are right in this point. But what about my suggestion of keeping the objects to save in a temporary list? Will check your e-mail.

I have problems syncing the grid with inserts and editing in the grid. Direct inserts in the dataset are ok, edits too. I can then iterate over the dataset and call SaveOrUpdate for every record/object

.
How to deal with deletes, I am unsure. Keeping the grid in sync is one problem, actually removing the objects another. As the rows are deleted from the dataset, I must use the OnRemove event to keep a list.

Why not give the dataset three lists: inserted, edited, deleted, which point to the objects? Then it would be easier to get hold of all changes.

Do you have any issues in using the OnObjectRemove event? You could just use it and add the object to your own list.

We're considering adding this "transaction" feature in the object manager itself, so implementing temporary solution like lists in the dataset is not being considered.

This works ok for me:



procedure TForm2.adsTestObjectRemove(Dataset: TDataSet; AObject: TObject);
begin
  DeleteSoftware.Add(AObject as TSoftware);
end;

procedure TForm2.btnDeleteClick(Sender: TObject);
begin
  adsTest.Delete;
end;

procedure TForm2.btnSaveToDBClick(Sender: TObject);
var
  Software: TSoftware;
begin
  Manager.Flush;
  adsTest.First;
  while not adsTest.eof do begin
    Manager.SaveOrUpdate(adsTest.Current<TSoftware>);
    adsTest.Refresh;
    adsTest.Next;
  end;
  for Software in DeleteSoftware do
    Manager.Remove(Software);
  DeleteSoftware.Clear;
end;

This does not work - the FNCGrid gets out of sync:
procedure TForm2.btnInsertClick(Sender: TObject);
begin
  adsTest.Insert;
//  adsTest.FieldByName('description').AsString := 'enter description';
//  adsTest.Post;
end;

When working with the dataset without having a mangager connected, you need a list for maintaining the objects that need to be removed. So why not have this list in the dataset?

Given a large dataset with many rows, the list of inserted/updated objects would be helpful too.

tx + greetings Bernd
Having a class handling this:

 type
    TDataSethelper<T> = class
      ToBeInserted : TList<T>;
      ToBeUpdated : TList<T>;
      ToBeDeleted : TList<T>;
     private
      FManager: TObjectManager;
      procedure SetManager(const Value: TObjectManager);
      property Manager: TObjectManager read FManager write SetManager;
     public
      constructor Create(aManager: TObjectManager);
      procedure AddToInsert(element: T);
      procedure AddToDelete(element: T);
      procedure AddToUpdate(element: T);
      procedure Persist;
    end;


You don't need to call Refresh on every iteration, you can do this:




procedure TForm2.btnSaveToDBClick(Sender: TObject);
var
  Software: TSoftware;
begin
  adsTest.First;
  while not adsTest.eof do begin
    Manager.SaveOrUpdate(adsTest.Current<TSoftware>);
    adsTest.Next;
  end;
  for Software in DeleteSoftware do
    Manager.Remove(Software);
  Manager.Flush;
  DeleteSoftware.Clear;
  adsTest.Refresh;
end;

BTW: Why is the Flush still needed? Doesn´t the SaveOrUpdate in the loop handle all changes?

Update operation doesn't immediately perform modifications in the database. It just adds the object to the manager - if the object is in the manager already, it does nothing.

It's only in the Flush that all modified objects are detected and updates are performed.

Just to get things right:


Manager.
Save() issues INSERT to the DB
Update() does nothing in the DB
SaveOrUpdate() may issue INSERT to the DB
Flush() issues UPDATE to the DB
Remove() issues DELETE in the DB




That's correct. Flush might also cause other types of UPDATES (which are inclusion/exclusion of an item in a collection) and also DELETE (if an item is excluded form a collection and has cascade type RemoveOrphan, which will cause the item to be deleted).