Sorting a detail list (with detail lists)

Hi,

I have a three level entity structure.  TEntityA contains a List of TEntityB (1st level detail). TEntityB contains two Lists of TEntityC1 and TEntityC2 (2nd detail level).

The issue I am having is that I need to perform an operation that uses the first level entities(TEntityB) but theses entities need to be sequentially ordered (I display data in a DevExpress TcxGrid, which takes care of the "on display sorting").  For this, I apply the following procedure:

procedure TSD_WellSchematic.SortCasingList(ADetailList: TList<TEntityB>);
var
  Comparer: IComparer<TEntityB>;
begin
  // Sort entities so we can iterate and draw in correct sequence
  Comparer := TDelegatedComparer<TEntityB>.Create(
    function(const Entity1, Entity2: TEntityB): Integer
    begin
      case CompareValue(Entity1.DoubleValue, Entity2.DoubleValue) of
        LessThanValue:
          result := -1;
        GreaterThanValue:
          result := 1;
      else
        result := 0;
      end;
    end);
  ADetailList.Sort(Comparer);
end;

The first thing I notice is that after the operation (sorting), particular records (that were moved by sorting) display values of other records when beginning to edit a cell. This however, is simply sorted by refreshing the TAureliusDataSet.

The greater problem lies in the fact that when I attempt to delete a record in one of the second level details (TEntityC1 or TEntityC2 list), I first get an AV followed by a "Bookmark not found".  Looking at the Call Stack, it fails in Aurelius.Bind.BaseDataset.TBaseAureliusDataset.InternalSetToRecord and  Aurelius.Bind.BaseDataset.TBaseAureliusDataset.InternalGotoBookmark.

Obviously a pointer is "lost" but what doesn't make sense to me, is that when I sort the list of TEntityB objects, the TEntityC1List and TEntityC2List properties shouldn't change and still point to the correct TList's which in turn still point to the correct entity objects.

Clearly there is a problem, so where is my thinking wrong? What am I missing? 

Of course I'd also like to know if there's a way to work around this.  Refreshing datasets does not seem to have an effect for the 2nd level lists; only for the first level (that is actually sorted).

Looking forward to your reply.  This is an interesting problem as I am working on programs that typically need to iterate records sorted by depth or date(time)….

Rgds, Mark 
I have been running some further debug sessions and perhaps important to note is the following:

I can edit (in the grids) the third level entities (C1 & C2) without any problem after sorting the second level entities (B). All is correctly updated in the database (SQLite in this case).  No issues with AV or Bookmarks. 

The problem only occurs when deleting a C1 or C2 entity. Also note that despite the AV and  Bookmark error, the entity is removed (also from database).  This leads me to think it's an internal (Aurelius) dataset bug; if I can edit the entity in the grid, clearly all pointers to lists and entities are still OK....

Hopefully you can help me with a solution (or temp workaround) rather quickly.  I am now stuck (sorting is a must) and the only alternative I see is to adjust the structure of my program and edit (/delete) third-level entities in modal dialogs.  However, that's not very elegant (or user friendly) and  quite some extra work.

Regards,
Mark

Hello Mark,


Please try to set property
Manager.DeferDestruction := True;
Where Manager is the TObjectManager object used to delete the entities (probably associated to your dataset).

Also, for ordering your lists, if you don't need to change the order dynamically, consider using OrderBy attribute:
http://www.tmssoftware.com/business/aurelius/doc/web/orderbyattribute.html
Hello Wagner,

I had come across the OrderBy attribute, but in this case I need dynamic sorting so it's not applicable.
I tried your other suggested solution (DeferDestruction) and it works.  I'll apply some further rigorous testing, but so far I can delete third-level entities without issue.

Could you perhaps elaborate a bit further - for my education - why this solves the problem?  I still fail to see the logic but that could be me, of course.... ;-)

Also, as I understand it, delete would normally destroy the entity object, but that is now deferred until the ObjectManager is destroyed - correct?

Thanks for your help!
Mark

Hi Mark,

Your understanding of DeferDestruction is correct.
The thing is since the object is destroyed in the middle of several operations, there might be a chance that such object is still being referred by other objects, and when something tries to access it, it will try to access a destroyed object, thus the error.
The most common situation is when the object is destroyed but it's still referenced in a TList that contains the object. If an entity with such list is flushed, Aurelius will try to inspect all objects in the list for proper operation, and since the object is destroyed, an AV is raised.