Access violation on "in between" entity class

Consider below declarations (some properties and getters/setters removed for readibility):

 // Entity TWellbore omitted - not relevant

 [Entity]
  [Table('Operation')]
  TOperation = class(TBaseEntity)
  private
    [Column('OperationType', [TColumnProp.Required], 15)]
    FOperationType: TOperationType;

    [Column('OperationName', [TColumnProp.Required], 50)]
    FOperationName: string;

    [Association([TAssociationProp.Lazy, TAssociationProp.Required], CascadeTypeAll - [TCascadeType.Remove])]
    [ForeignKey('FK_Operation_Wellbore')]
    [JoinColumn('ID_Parent', [TColumnProp.Required], 'ID')]
    FWellbore: Proxy<TWellbore>;
    function GetWellbore: TWellbore;
    procedure SetWellbore(const Value: TWellbore);
  public
    property OperationType: TOperationType read FOperationType write FOperationType;
    property OperationName: string read FOperationName write FOperationName;
    property Wellbore: TWellbore read GetWellbore write SetWellbore;
  end;

// This is the "in between class that I decorate with a ManyValuedAssociation Days
  [Entity]
  TOperation_Day = class(TOperation)
  private
    [ManyValuedAssociation([TAssociationProp.Lazy, TAssociationProp.Required], CascadeTypeAllRemoveOrphan,
      'FOperation_Day')]
    FDays: Proxy<TList<TDay>>;
    function GetDays: TList<TDay>;
  public
    property Days: TList<TDay> read GetDays;
  end;

  [Entity]
  [Table('Day')]
  TDay = class(TBaseEntity)
  private

    [Column('ReportDate', [TColumnProp.Required])]
    FReportDate: TDateTime;

    [Association([TAssociationProp.Lazy], CascadeTypeAll - [TCascadeType.Remove])]
    [ForeignKey('FK_Day_Operation')]
    [JoinColumn('ID_Parent', [TColumnProp.Required], 'ID')]
    FOperation_Day: Proxy<TOperation_Day>;

    function GetOperation_Day: TOperation_Day;
    procedure SetOperation_Day(const Value: TOperation_Day);
  public
    property ReportDate: TDateTime read FReportDate write FReportDate;
    property Operation_Day: TOperation_Day read GetOperation_Day write SetOperation_Day;
  end;

On DBSchema.UpdateDatabase, I get an access violation in TTableCreator.CreateTable. To be specific in Table.Name := MappedTable.Name when EntityType in the line above is TOperation_Day.

Is this construction ("in between class") not allowed or am I doing something wrong?

On another note: I am applying this decorating to have a light-weight top class for fast data navigation. The derived class with several (!) many-valued associations is then used for data editing. However, I am now wondering if this is worth the "effort". Will loading entities be any slower when they include lazy-loading associations? Probably not, but I am still curious to hear why my above "construction" fails...

Correct, it's not allowed. Every class marked with [Entity] attribute must have a table associated to it, unless it's part of a single-table hierarchy.

If you're talking about lazy-loaded many-valued associations, it won't make a different to load a class with lots of such associations or not, that's the purpose of lazy-loading. Aurelius will only load the lists if the respective property is read.

Hi Wagner,

Thanks for confirming that every entity must have a table. I more or less figured that out after submitting my post.

With what I was trying to do, I clearly "designed myself" into something that's way too complex and not necessary. The reason for this is that I am building an application in which I have a hierarchy of entities that runs 6-7 levels deep. As I expect issues to arise from this when performing certain tasks, I attempted to somehow "break that chain" and make the entities easier to handle. After some further thought, I now have the - much easier - solution. FWIW, I am posting it here as others may run into the same challenge.

  1. I can design the top-level entities (TWell -> TWellbore -> TOperation) with many-valued associations to their children (all lazy-loaded) so no consequences for loading speed.
  2. At the fourth level (TDay) I "break the chain". Here, the TDay has an association (M-1) to TOperation but TOperation does NOT have a many-valued association (1-M) to TDay. Note that there will be several other entities at this level - logically linked to TOperation - that I will define like TDay.
  3. Whenever I need to access entities at the TDay level, I simply perform a selection query. Something like: FObjMgr.Find<TDay>.Add(Linq['Operation.Id'] = AnOperation.Id).List. Prior to saving, I set MyDataSetOperation.AsObject := AnOperation.

This works fine without issues and removes all unnecessary and complex inheritance issues.

1 Like