Hi,
I have declared some entities, derived from an abstract entity (FYI: the entity hierarchy is Well -> Wellbore -> Operation):
uses
SysUtils,
Generics.Collections,
Aurelius.Mapping.Attributes,
Aurelius.Types.Blob,
Aurelius.Types.DynamicProperties,
Aurelius.Types.Nullable,
Aurelius.Types.Proxy,
Entities.WellDoc_Enums;
type
TBaseEntity = class;
TOperation = class;
TWell = class;
TWellbore = class;
[AbstractEntity]
[Table('BaseEntity')]
[Id('FID', TIdGenerator.Uuid36)]
TBaseEntity = class
private
[Column('ID', [TColumnProp.Required], 36)]
FID: string;
[Column('ParentID', [], 36)]
FParentID: Nullable<string>;
[Column('Created', [])]
FCreated: Nullable<TDateTime>;
[Column('Modified', [])]
FModified: Nullable<TDateTime>;
[Column('RowVersion', [TColumnProp.Required])]
[Version]
FRowVersion: Integer;
[Column('QC_Level', [])]
FQC_Level: TQC_Level;
public
property Id: string read FID write FID;
property ParentID: Nullable<string> read FParentID write FParentID;
property Created: Nullable<TDateTime> read FCreated write FCreated;
property Modified: Nullable<TDateTime> read FModified write FModified;
property RowVersion: Integer read FRowVersion write FRowVersion;
property QC_Level: TQC_Level read FQC_Level write FQC_Level;
end;
[Entity]
[Table('Operation')]
TOperation = class(TBaseEntity)
private
[Column('OperationType', [TColumnProp.Required], 10)]
FOperationType: string;
[Column('OperationName', [TColumnProp.Required], 50)]
FOperationName: string;
[Association([TAssociationProp.Lazy, TAssociationProp.Required], CascadeTypeAll - [TCascadeType.Remove])]
[JoinColumn('ParentID', [TColumnProp.Required], 'ID')]
FWellbore: Proxy<TWellbore>;
function GetWellbore: TWellbore;
procedure SetWellbore(const Value: TWellbore);
public
property OperationType: string read FOperationType write FOperationType;
property OperationName: string read FOperationName write FOperationName;
property Wellbore: TWellbore read GetWellbore write SetWellbore;
end;
[Entity]
[Table('Well')]
TWell = class(TBaseEntity)
private
[Column('WellName', [TColumnProp.Required], 50)]
FWellName: string;
[Column('WellOperator', [TColumnProp.Required], 50)]
FWellOperator: string;
[ManyValuedAssociation([TAssociationProp.Lazy, TAssociationProp.Required], [TCascadeType.SaveUpdate,
TCascadeType.Merge, TCascadeType.Remove], 'FWell')]
FWellbores: Proxy<TList<TWellbore>>;
function GetWellbores: TList<TWellbore>;
public
constructor Create;
destructor Destroy; override;
property WellName: string read FWellName write FWellName;
property WellOperator: string read FWellOperator write FWellOperator;
property Wellbores: TList<TWellbore> read GetWellbores;
end;
[Entity]
[Table('Wellbore')]
TWellbore = class(TBaseEntity)
private
[Column('Rank', [TColumnProp.Required])]
FRank: Integer;
[Column('WellboreName', [TColumnProp.Required], 50)]
FWellboreName: string;
[Column('MD_Start', [TColumnProp.Required])]
FMD_Start: Double;
[Association([TAssociationProp.Lazy, TAssociationProp.Required], CascadeTypeAll - [TCascadeType.Remove])]
[JoinColumn('ParentID', [TColumnProp.Required], 'ID')]
FWell: Proxy<TWell>;
[ManyValuedAssociation([TAssociationProp.Lazy, TAssociationProp.Required], [TCascadeType.SaveUpdate,
TCascadeType.Merge, TCascadeType.Remove], 'FWellbore')]
FOperations: Proxy<TList<TOperation>>;
function GetWell: TWell;
procedure SetWell(const Value: TWell);
function GetOperations: TList<TOperation>;
public
constructor Create;
destructor Destroy; override;
property Rank: Integer read FRank write FRank;
property WellboreName: string read FWellboreName write FWellboreName;
property MD_Start: Double read FMD_Start write FMD_Start;
property Well: TWell read GetWell write SetWell;
property Operations: TList<TOperation> read GetOperations;
end;
When I run a quick test application and perform a DBSchema.BuildDatabase or UpdateDatabase, I get the following exception:
Project VclTest.exe raised exception class EAureliusOdbcException with message 'Error -1: [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Column names in each table must be unique. Column name 'ParentID' in table 'Operation' is specified more than once.'.
Checking the SQL executed (in TSQLPerformer.ExecuteSQL), this is indeed the case:
CREATE TABLE Operation (
ID VARCHAR(36) NOT NULL,
ParentID VARCHAR(36) NULL, // <<<<<<<
Created DATETIME NULL,
Modified DATETIME NULL,
RowVersion INT NOT NULL,
QC_Level INT NULL,
OperationType VARCHAR(10) NOT NULL,
OperationName VARCHAR(50) NOT NULL,
ParentID VARCHAR(36) NOT NULL, // <<<<<<< (and not null ??)
CONSTRAINT PK_Operation PRIMARY KEY (ID))
At first I thought it was somehow associated to the use of [AbstractEntity], but changing this to [Entity] had no effect.
I noticed that in several examples, AutoMapping was used. For the sake of trying, I added , AutoMapping to all (base)entity attributes and commented out all [Column] attributes:
[AbstractEntity, AutoMapping]
[Table('BaseEntity')]
[Id('FID', TIdGenerator.Uuid36)]
TBaseEntity = class
private
// [Column('ID', [TColumnProp.Required], 36)]
FID: string;
// [Column('ParentID', [], 36)]
FParentID: Nullable<string>;
// [Column('Created', [])]
FCreated: Nullable<TDateTime>;
// [Column('Modified', [])]
FModified: Nullable<TDateTime>;
// [Column('RowVersion', [TColumnProp.Required])]
[Version]
FRowVersion: Integer;
// [Column('QC_Level', [])]
FQC_Level: TQC_Level;
public
property Id: string read FID write FID;
property ParentID: Nullable<string> read FParentID write FParentID;
property Created: Nullable<TDateTime> read FCreated write FCreated;
property Modified: Nullable<TDateTime> read FModified write FModified;
property RowVersion: Integer read FRowVersion write FRowVersion;
property QC_Level: TQC_Level read FQC_Level write FQC_Level;
end;
[Entity, AutoMapping]
[Table('Operation')]
TOperation = class(TBaseEntity)
private
// [Column('OperationType', [TColumnProp.Required], 10)]
FOperationType: string;
// [Column('OperationName', [TColumnProp.Required], 50)]
FOperationName: string;
[Association([TAssociationProp.Lazy, TAssociationProp.Required], CascadeTypeAll - [TCascadeType.Remove])]
[JoinColumn('ParentID', [TColumnProp.Required], 'ID')]
FWellbore: Proxy<TWellbore>;
function GetWellbore: TWellbore;
procedure SetWellbore(const Value: TWellbore);
public
property OperationType: string read FOperationType write FOperationType;
property OperationName: string read FOperationName write FOperationName;
property Wellbore: TWellbore read GetWellbore write SetWellbore;
end;
[Entity, AutoMapping]
[Table('Well')]
TWell = class(TBaseEntity)
private
// [Column('WellName', [TColumnProp.Required], 50)]
FWellName: string;
// [Column('WellOperator', [TColumnProp.Required], 50)]
FWellOperator: string;
[ManyValuedAssociation([TAssociationProp.Lazy, TAssociationProp.Required], [TCascadeType.SaveUpdate,
TCascadeType.Merge, TCascadeType.Remove], 'FWell')]
FWellbores: Proxy<TList<TWellbore>>;
function GetWellbores: TList<TWellbore>;
public
constructor Create;
destructor Destroy; override;
property WellName: string read FWellName write FWellName;
property WellOperator: string read FWellOperator write FWellOperator;
property Wellbores: TList<TWellbore> read GetWellbores;
end;
[Entity, AutoMapping]
[Table('Wellbore')]
TWellbore = class(TBaseEntity)
private
// [Column('Rank', [TColumnProp.Required])]
FRank: Integer;
// [Column('WellboreName', [TColumnProp.Required], 50)]
FWellboreName: string;
// [Column('MD_Start', [TColumnProp.Required])]
FMD_Start: Double;
[Association([TAssociationProp.Lazy, TAssociationProp.Required], CascadeTypeAll - [TCascadeType.Remove])]
[JoinColumn('ParentID', [TColumnProp.Required], 'ID')]
FWell: Proxy<TWell>;
[ManyValuedAssociation([TAssociationProp.Lazy, TAssociationProp.Required], [TCascadeType.SaveUpdate,
TCascadeType.Merge, TCascadeType.Remove], 'FWellbore')]
FOperations: Proxy<TList<TOperation>>;
function GetWell: TWell;
procedure SetWell(const Value: TWell);
function GetOperations: TList<TOperation>;
public
constructor Create;
destructor Destroy; override;
property Rank: Integer read FRank write FRank;
property WellboreName: string read FWellboreName write FWellboreName;
property MD_Start: Double read FMD_Start write FMD_Start;
property Well: TWell read GetWell write SetWell;
property Operations: TList<TOperation> read GetOperations;
end;
This works and creates the tables as expected! However, I am failing to understand why. Is this a bug in creating the required SQL or am I missing/misunderstanding a certain requirement (e.g. on using AbstractEntity with associations)?


