Data not saved to database

Hello,


we have encountered a problem after upgrading to Aurelius 2.6.1.

We have two tables connected together using FK.
If I get the parent object and modify only properties on this object, the changes are saved to DB

However, if I modify any properties on it's child object, only the changes to the child object is saved to DB and the changes to the parent is not.

The following code works as expected:

  longTrendItem := FObjectManager.Find<TLongTrendItem>().Add(
    TLinq.Eq('VesselId', aVesselId) and
    TLinq.Eq('Description', aDescription)).UniqueResult;

  if Assigned(longTrendItem) then
  begin
    longTrendItem.IsDirty := not longTrendItem.IsDirty;
    longTrendItem.GraphMaximumValue := longTrendItem.GraphMaximumValue + 1;
  end;
  FObjectManager.Flush;

This code does not save changes to the longTrendItem object...

  longTrendItem := FObjectManager.Find<TLongTrendItem>().Add(
    TLinq.Eq('VesselId', aVesselId) and
    TLinq.Eq('Description', aDescription)).UniqueResult;

  if Assigned(longTrendItem) then
  begin
    longTrendItem.IsDirty := not longTrendItem.IsDirty;
    longTrendItem.GraphMaximumValue := longTrendItem.GraphMaximumValue + 1;

    if Assigned(longTrendItem.DiagnosticTypeId) then
    begin
      longTrendItem.DiagnosticTypeId.YellowOffset := longTrendItem.DiagnosticTypeId.YellowOffset;
    end;
  end;
  FObjectManager.Flush;

Any suggestions??

Thanks and best regards
Kjetil

Did you try ObjectManager.SaveOrUpdate(longTrendItem)?

A little sidenote on longTrendItem.DiagnosticTypeId. You can make this longTrendItem.DiagnosticType (without the Id) by choosing another (model) name in the datamodeler but keep the name in the database original. Seems more logical to access this field because it is not an Id but another object.

No, I did not try the SaveOrUpdate() method.


Shouldn't the ObjectManager keep track of all the changes on the loaded objects and update the DB on the Flush() method?

It used to work this way at least.

Thanks for the tip. Yes, it sure would make more sense to change the name there.

-Kjetil

I think that in your situation the linked object is saved to the database first and the parent object is probably re-read from the database thus overriding your changes. You can check this with an SQL monitor or WireShark.

If that is the case then update and flush the parent object first. It doesn't make a difference in performance.

ObjectManager.SaveOrUpdate(anObject);
ObjectManager.FlushSingleObject(anObj);

FlushSingleObject does not exist but you can add it with this object helper:

 TObjectManagerHelper = class helper for TObjectManager
  public
    procedure FlushSingleObject(const anObj: TObject);
  end;

implementation

procedure TObjectManagerHelper.FlushSingleObject(const anObj: TObject);
begin
  Self.PerformUpdate(anObj, nil);
end;

Scott

By the way; yes i think this is a problem with Aurelius. My solution above is just a work-around.

Do you have more details about this problem? What is the mapping you get?

Are you able to reproduce this issue in a simple project using SQLite?

Hi,

not sure what you mean by "mapping I get". This is the "generated" code:


[Entity]
  [Table('LongTrendItem')]
  [Id('FLongTrendItemId', TIdGenerator.IdentityOrSequence)]
  TLongTrendItem = class
  private
    [Column('LongTrendItemId', [TColumnProp.Required, TColumnProp.NoInsert, TColumnProp.NoUpdate])]
    FLongTrendItemId: integer;
    
    [Column('VesselStatus', [TColumnProp.Required])]
    FVesselStatus: integer;
    
    [Column('LongTrendItemName', [TColumnProp.Required], 100)]
    FLongTrendItemName: string;
    
    [Column('Description', [TColumnProp.Required], 100)]
    FDescription: string;
    
    [Column('DescriptionLong', [TColumnProp.Required])]
    FDescriptionLong: string;
    
    [Column('GraphMinimumValue', [TColumnProp.Required])]
    FGraphMinimumValue: double;
    
    [Column('GraphMaximumValue', [TColumnProp.Required])]
    FGraphMaximumValue: double;
    
    [Column('IsDirty', [TColumnProp.Required])]
    FIsDirty: boolean;
    
    [Association([TAssociationProp.Lazy], [])]
    [JoinColumn('DiagnosticTypeId', [], 'DiagnosticTypeId')]
    FDiagnosticTypeId: Proxy<TDiagnosticType>;
    
    [Association([TAssociationProp.Lazy, TAssociationProp.Required], [])]
    [JoinColumn('UnitId', [TColumnProp.Required], 'UnitId')]
    FUnitId: Proxy<TKspUnit>;
....    


  [Entity]
  [Table('DiagnosticType')]
  [Id('FDiagnosticTypeId', TIdGenerator.IdentityOrSequence)]
  TDiagnosticType = class
  private
    [Column('DiagnosticTypeId', [TColumnProp.Required, TColumnProp.NoInsert, TColumnProp.NoUpdate])]
    FDiagnosticTypeId: integer;
    
    [Column('DiagnosticTypeName', [TColumnProp.Required], 100)]
    FDiagnosticTypeName: string;
    
    [Column('YellowOffset', [TColumnProp.Required])]
    FYellowOffset: double;
....

I working with SQL Server 2008 R2 so I have not tried against SQLite.

Thanks for any inputs. 
I will try the suggestions from Scott but of course I'd rather have a permanent fix then using a workaround.

-Kjetil

Update:

Looks like I found another workaround. If I modify (and load) the child object first, before changing the parent object, both tables are updated. So in my example above, this works:

This code works...

  longTrendItem := FObjectManager.Find<TLongTrendItem>().Add(
    TLinq.Eq('VesselId', aVesselId) and
    TLinq.Eq('Description', aDescription)).UniqueResult;

  if Assigned(longTrendItem) then
  begin
    if Assigned(longTrendItem.DiagnosticTypeId) then
    begin
      longTrendItem.DiagnosticTypeId.YellowOffset := longTrendItem.DiagnosticTypeId.YellowOffset + 1;
    end;

    longTrendItem.IsDirty := not longTrendItem.IsDirty;
    longTrendItem.GraphMaximumValue := longTrendItem.GraphMaximumValue + 1;

  end;
  FObjectManager.Flush;

Doesn't TDiagnosticType have a reference back to TLongTrendItem?

No, Only reference from TLongTrendItem to TDiagnosticType.

We confirmed this is a bug in Aurelius introduced in version 2.6.

It's fixed now, we haved released a new version (2.6.2) with the fix. Thanks for reporting.

OK, thanks for the quick reply and fix. I will try the new version tomorrow.

You're welcome :-)