Hello.
I have a project with Aurelius 2.6. When in modal form user press "Cancel", I refresh object with ObjManager.Refresh, because some data in object may be changed in form. It's work when I use simple object, but when I try to use mapped object with ManyValuedAssociation - I got an exception when try to access ManeValue-list.
I create a test project, which repeats error.
At first, create a test tables (Oracle syntax):
create table test_test.master
(
id number,
title varchar2(100 char)
)
;
alter table test_test.master
add constraint pk_master primary key (ID);
create table test_test.detail
(
id number,
master_id number not null,
val number
)
;
alter table test_test.detail
add constraint pk_detail primary key (ID);
alter table test_test.detail
add constraint fk_detail_master foreign key (MASTER_ID)
references test_test.master (ID);
Two simple tables, master and detail. Insert in master one row with ID = 1. Detail is empty (or not, it does not matter).
For Delphi-mapping I use Data Modeler db reverse (with some property renames):
TDetail = class;
TMaster = class;
[Entity]
[Table('DETAIL')]
[Id('FID', TIdGenerator.None)]
TDetail = class
private
[Column('ID', [TColumnProp.Required])]
FID: double;
[Column('VAL', [])]
FValue: Nullable<double>;
[Association([TAssociationProp.Lazy, TAssociationProp.Required], CascadeTypeAll - [TCascadeType.Remove])]
[JoinColumn('MASTER_ID', [TColumnProp.Required], 'ID')]
FMaster: Proxy<TMaster>;
function GetMaster: TMaster;
procedure SetMaster(const Value: TMaster);
public
property ID: double read FID write FID;
property Value: Nullable<double> read FValue write FValue;
property Master: TMaster read GetMaster write SetMaster;
end;
[Entity]
[Table('MASTER')]
[Id('FID', TIdGenerator.None)]
TMaster = class
private
[Column('ID', [TColumnProp.Required])]
FID: double;
[Column('TITLE', [], 400)]
FTitle: string;
[ManyValuedAssociation([TAssociationProp.Lazy, TAssociationProp.Required], [TCascadeType.SaveUpdate, TCascadeType.Merge], 'FMaster')]
FDetails: Proxy<TList<TDetail>>;
function GetDetails: TList<TDetail>;
public
constructor Create;
destructor Destroy; override;
property ID: double read FID write FID;
property Title: string read FTitle write FTitle;
property Details: TList<TDetail> read GetDetails;
end;
implementation
{ TDetail}
function TDetail.GetMaster: TMaster;
begin
result := FMaster.Value;
end;
procedure TDetail.SetMaster(const Value: TMaster);
begin
FMaster.Value := Value;
end;
{ TMaster}
constructor TMaster.Create;
begin
FDetails.SetInitialValue(TList<TDetail>.Create);
end;
destructor TMaster.Destroy;
begin
FDetails.DestroyValue;
inherited;
end;
function TMaster.GetDetails: TList<TDetail>;
begin
result := FDetails.Value;
end;
And then I use this code:
procedure TForm1.ButtonClick(Sender: TObject);
var
M: TMaster;
begin
M := Manager.Find<TMaster>(1);
M.Title := 'new title; detail count = ' + IntToStr(M.Details.Count);
Manager.Refresh(M);
ShowMessage(IntToStr(M.Details.Count));
end;
When I try to call M.Details.Count second time, I got an exception:
What I do wrong? Is there an error in mapping code?
Now I use small trick to do refresh, but without refresh:
var
M: TMaster;
vID: Double;
begin
M := Manager.Find<TMaster>(1);
M.Title := 'new title; detail count = ' + IntToStr(M.Details.Count);
vID := m.ID;
Manager.Evict(M);
M.Free;
M := Manager.Find<TMaster>(vID);
ShowMessage(IntToStr(M.Details.Count));
It's work, but it's not good decission - in app may be another links to this object...