I am trying to do an One-to-One mapping following the instructions of this forum post: https://www.tmssoftware.com/site/forum/forum_posts.asp?TID=12928&title=how-to-map-onetoone-association as follows:
*** CODE BEGIN
[Entity]
[table("person_address")]
[Id("FPersonId", TIdGenerator.None)]
TPersonAddress = class
strict private
[Column("person_id", [TColumnProp.Unique, TColumnProp.Required, TColumnProp.NoUpdate])]
FPersonId: Integer;
[Column("zip_code", [], 60)]
FZipCode: String;
published
property PersonId: Integer read FPersonId write FPersonId;
property ZipCode: String read FZipCode write FZipCode;
end;
[Entity]
[Table("person")]
[Sequence("seq_person_id")]
[Id("FId", TIdGenerator.IdentityOrSequence)]
[Inheritance(TInheritanceStrategy.JoinedTables)]
TPerson = class
strict private
[Column("id", [TColumnProp.Unique, TColumnProp.Required, TColumnProp.NoUpdate])]
FId: Integer;
[Column("name", [], 60)]
FName: String;
[ManyValuedAssociation([], CascadeTypeAllRemoveOrphan)]
[ForeignJoinColumn("person_id", [TColumnProp.Required])]
FAddress: TList<TPersonAddress>;
private
function GetAddress: TPersonAddress;
procedure SetAddress(const Value: TPersonAddress);
public
constructor Create;
published
property Id: Integer read FId write FId;
property Name: String read FName write FName;
property Address: TPersonAddress read GetAddress write SetAddress;
end;
[Entity]
[Table("customer")]
[PrimaryJoinColumn("person_id")]
TCustomer = class(TPerson)
strict private
[Column("total_invoices", [])]
FTotalInvoices: Integer;
published
property TotalInvoices: Integer read FTotalInvoices write FTotalInvoices;
end;
CODE END ***
In the application, we have three classes: a base class "TPerson" (pk_fieldname: "id"); a child class TCustomer (pk_fieldname: "person_id"); and the TPersonAddress (pk_fieldname: "person_id") class which have a One-to-One relationship with the base class TPerson.
When i try to persist an instance of TCustomer with an assigned Address property i get the error "Column person_address.person_id cannot be repeated in INSERT statement".
Srdic,
I had a similar problem in one of my projects. Here's what I did for FID field in TPerson that worked for me:
[Column('ID', [TColumnProp.Required])]
FId: Integer;
I also wonder why you are not using a Person: TPerson association instead of FPersonID. Recommend you try:
[Association([TAssociationProp.Lazy], CascadeTypeAll - [TCascadeType.Remove])]
[JoinColumn('person_id', [TColumnProp.Required,TColumnProp.NoUpdate])]
FPerson: Proxy<TPerson>;
function GetPerson: TPerson;
procedure SetPerson(Value: TPerson);
property Person: TPerson read GetPerson write SetPerson;
implementation
TPerson.GetPerson: TPerson;
begin
Result := FPerson.Value;
end;
TPerson.SetPerson(Value: TPerson);
begin
FPerson.Value := Value;
end;
Last, I notice you are using the quotation character (") instead of apostrophe (') for strings in your attribute definitions. I am not sure if this makes a difference, but i have not seen it used this way in the documentation.
Hope it works for you. If not, I'm sure Wagner will have the right solution.
Terry,
I submitted a feature request (req. 2564) to implement a native one-to-one mapping like the frameworks of other languages (for example, Java Hibernate). Please add your vote.
I will wait for Wagner's reply before apply your workaround. Thanks for your suggestion.
Regards
Fabricio, I see that you have also sent the same question via private e-mail. I will repeat the answer here so it might benefit others:
The root of the problem is here:
TPersonAddress = class
strict private
[Column("person_id", [TColumnProp.Unique, TColumnProp.Required, TColumnProp.NoUpdate])]
FPersonId: Integer;
PersonId is an association to a TPerson object. It should be declared this way:
TPersonAddress = class
strict private
[Association([], CascadeTypeAllButRemove)]
[JoinColumn("person_id", [TColumnProp.Unique, TColumnProp.Required, TColumnProp.NoUpdate])]
FPersonId: TPerson;
And then in TPerson you should map it this way:
[ManyValuedAssociation([], CascadeTypeAllRemoveOrphan, ‘FPersonId')]
FAddress: TList<TPersonAddress>;
Pointing that the other side of TPerson.FAddress association is TPersonAddress.FPersonId.