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)?