Dbo does not persist changes to fields, only collections

Added by Christian Meyer about 1 year ago

Hi there =)

I don't have a clue as to why this does not work.
My save routine saves some parts that are changed but not others.

Here are some additional infos


/// Object::persist looks like this:
{
    // As you can see there are field items that are unused in the save process at the moment

    // just recently found out that this would be unnecessary if Object would be Child class of Wt::Dbo::Dbo
    // this will be changed later and is hopefully not the culprit ... but it's on the agenda! ;-)
    Wt::Dbo::field(a, selfPtr, "selfPtr"); 

    Wt::Dbo::belongsTo(a, slotPtr, "calendarslot_calendaritem");
    Wt::Dbo::hasMany(a, collectionForRelation, Wt::Dbo::ManyToMany, "collection_object");
    Wt::Dbo::field(a, fieldDate, "planned_date");

    Wt::Dbo::field(a, fieldTimeStart, "planned_start");
    Wt::Dbo::field(a, fieldTimeEnd, "planned_duration");

    Wt::Dbo::field(a, t_confirmed_start, "confirmed_start");
    Wt::Dbo::field(a, t_confirmed_end, "confirmed_duration");

    Wt::Dbo::field(a, t_change_before, "changed_before");

    Wt::Dbo::field(a, fieldStringTitle, "title");
    Wt::Dbo::field(a, fieldStringInfo, "info");
}

/// Just for reference:
/// objItem := const Object*;
/// objPtr  := Wt::Dbo::ptr<Object>;
/// saveObject := Object*;

And here is the Save Routine that doesn't work as I think it should!

Wt::Dbo::Transaction t(DboSession::dataSession());

saveObject = objPtr.modify();

saveObject->collectionForRelation.clear();

for (CheckboxWithCollectionPtr *a : vec_CheckboxesWithPtr)
{
  // add to Collection for each item in vec_CheckboxesWithPtr that is checked
  if(a->isChecked())
  {
    // This Part is actually persisted even through reloads
    saveObject->collectionForRelation.insert(a->getPtr());
  }
}

// This part is not persisted
saveObject->fieldDate = dateEdit->date();
saveObject->fieldTimeStart = timeEdit_start->time();
saveObject->fieldTimeEnd = timeEdit_end->time();
saveObject->fieldStringTitle = lineEdit_Title->text();
saveObject->fieldStringInfo = lineEdit_Info->text();

Wt::log("notice") << "Flush Changes: " << saveObject->toString();
objPtr.flush();
if(t.commit())
{
  objItem = objPtr.get();
  Wt::log("notice") << "Flush Success: " << objItem->toString();
}

After commit a Widget is created that includes all of these Information and is displayed as it should!

Log shows that it was successful as well:

[/ VHyoYWmF0TviEISH] [notice] "Flush Changes: Date: 13.09.2019; Start: 07:00; End: 08:00; Title: Testitem in 2; Info: 13th 7-8" 
commit transaction
[/ VHyoYWmF0TviEISH] [notice] "Flush Success: Date: 13.09.2019; Start: 07:00; End: 08:00; Title: Testitem in 2; Info: 13th 7-8" 

After reload of the page then, there is an item created ... at the position where it should be, but without any information displayed.

In the Constructor I have this:

    
if(objItem == nullptr)
{
  // This never gets Called, as it's never shown in the logs
  // I just wanted to make sure it gets loaded
  Wt::log("notice") << "Constructor: objItem == nullptr";
  Wt::Dbo::Transaction t(DboSession::dataSession());
  objItem = objPtr.get();
}

Wt::log("notice") << "Constructor with Object: " << objItem->toString();

And for Items that were created just in the code, the log looks like this:

[/ VHyoYWmF0TviEISH] [notice] "Constructor with Object: Date: 13.09.2019; Start: 07:30; End: 08:45; Title: Testing Title; Info: Testing Info" 

The others with the help of the Widget, look like this:

[/ VHyoYWmF0TviEISH] [notice] "Constructor with Object: Date: ; Start: ; End: ; Title: ; Info: " 

The Item that was created in the code can be manipulated, but only the collection parts, not the field parts.

If there is any hint to get an idea of why that is messing up, please let me know.

Dbo::backend is SQLite3, Wt Version is 4.1.0, built and running on Ubuntu from source

What I understand from the way it behaves, is that an Object is created in the DB and persisted... but the changes for it are in parts somewhere going missing.

I will try to create a minimal Program to replicate ... but if you see something in the meantime, please let me know =)

Cheers
Christian


Replies (2)

[SOLVED]: Dbo does not persist changes to fields, only collections - Added by Christian Meyer about 1 year ago

So, just after I finished describing the Problem and checking the logs again ...

I noticed that an update on the object is called as the collection is updated ... but not on commit,
even though the Transmission is still active and no flush called on the ptr.

So now I moved the updating of the field elements in front, before setting the new relations ... and voila!
It is saved as it should and can be read on reload ...

So thank you for your time, and I hope this might help someone else =)

Question is, if that is the way it should behave...

Cheers
Christian

RE: Dbo does not persist changes to fields, only collections - Added by Koen Deforche about 1 year ago

Hey,

Wt::Dbo only takes a call to 'modify()' as an indication that you are modifying the object. But it will flush dirty objects whenever a query needs to be done (to make sure dirty changes are consistent with the result of the query). In practice that means that you should do the modification immediately when calling modify() and not hold on to the returned pointer of modify().

We could probably solve this in Wt::Dbo by letting modify() return a smart pointer type, rather than a raw pointer, whose destructor is being tracked to do the dirty indication.

Regards,
koen

(1-2/2)