Hello!
I have the error, mentioned in the Topic title and I'm stuck. I checked other articles, but haven't found the solution.
Using Win32 app that saves a document through XData service, the error happens while saving.
The objects
Note: The classes are massively simplified. The classes are done winth Data modeler (latest version)
A TDocument can contain many TDocItems, each item has a TProduct.
[Entity]
[Table('doc_headers')]
[Id('FId', TIdGenerator.IdentityOrSequence)]
TDocument = class
private
[Column('ID', [TColumnProp.Required, TColumnProp.NoInsert, TColumnProp.NoUpdate])]
FId: Integer;
FBusinessYear: string;
FDocId: Integer;
[Association([TAssociationProp.Lazy, TAssociationProp.Required], CascadeTypeAll - [TCascadeType.Remove])]
[JoinColumn('DOC_TYPE', [TColumnProp.Required], 'ID')]
FDocType: Proxy<TTypeDocument>;
[Association([TAssociationProp.Lazy, TAssociationProp.Required], CascadeTypeAll - [TCascadeType.Remove])]
[JoinColumn('PARTNER_ID', [TColumnProp.Required], 'ID')]
FPartner: Proxy<TPartner>;
[ManyValuedAssociation([TAssociationProp.Lazy, TAssociationProp.Required], [TCascadeType.SaveUpdate, TCascadeType.Merge, TCascadeType.Remove], 'FHeader')]
FItems: Proxy<TList<TDocItem>>;
public
constructor Create;
destructor Destroy; override;
property Id: Integer read FId write FId;
property BusinessYear: string read FBusinessYear write FBusinessYear;
property DocId: Integer read FDocId write FDocId;
property DocType: TTypeDocument read GetDocType write SetDocType;
property Partner: TPartner read GetPartner write SetPartner;
property Items: TList<TDocItem> read GetItems;
end;
[Entity]
[Table('doc_items')]
[Id('FIdx', TIdGenerator.None)]
[Id('FHeader', TIdGenerator.None)]
TDocItem = class
private
[Column('IDX', [TColumnProp.Required])]
FIdx: Integer;
[Column('QTY', [TColumnProp.Required], 23)]
FQty: Double;
[Association([TAssociationProp.Lazy, TAssociationProp.Required], CascadeTypeAll - [TCascadeType.Remove])]
[JoinColumn('HEADER_ID', [TColumnProp.Required], 'ID')]
FHeader: Proxy<TDocument>;
[Association([TAssociationProp.Lazy, TAssociationProp.Required], CascadeTypeAll - [TCascadeType.Remove])]
[JoinColumn('PRODUCT_ID', [TColumnProp.Required], 'ID')]
FProduct: Proxy<TProduct>;
public
property Idx: Integer read FIdx write FIdx;
property Qty: Double read FQty write FQty;
property Header: TDocument read GetHeader write SetHeader;
property Product: TProduct read GetProduct write SetProduct;
end;
[Entity]
[Table('products')]
[Id('FId', TIdGenerator.None)]
TProduct = class
private
[Column('ID', [TColumnProp.Required])]
FId: Integer;
[Column('NAME', [], 255)]
FName: Nullable<string>;
public
constructor Create;
destructor Destroy; override;
property Id: Integer read FId write FId;
property Name: Nullable<string> read FName write FName;
end;
Client code
procedure TForm1.SaveNewDocument(Sender: TObject);
var newDoc: TDocument;
begin
var EasyService := Client.Service<IEasyService>;
newDoc := TDocument.Create;
newDoc.DocType := EasyService.GetDocType(1);
newDoc.Partner := EasyService.GetPartner(3);
newDoc.DateExpire := Now;
newDoc.DateEntry := Now;
var itm := TDocItem.Create;
itm.Product := EasyService.GetProduct(10); // Add existing product
itm.Qty := 2;
itm.PriceRetail := itm.Product.Prices[0].PriceRetail;
newDoc.Items.Add(itm);
EasyService.SaveDocument(newDoc);
end;
The service
Service method code
Basically just prepares and saves the document
function TEasyService.SaveDocument(Doc: TDocument): TRestResult;
var
par: TDocParam;
itm: TDocItem;
Statement: IDBStatement;
begin
try
Result := TRestResult.Create;
var mngr := TXDataOperationContext.Current.CreateManager;
{$REGION 'Preparation'}
Doc.DocTime := Now;
// Get latest DocId+1...
if (Doc.DocId=0) and Assigned(Doc.DocType) then begin
var lastDoc := mngr.Find<TDocument>
.Where(Dic.Document.DocType.Id = Doc.DocType.Id)
.Where(Dic.Document.BusinessYear = Doc.BusinessYear)
.OrderBy(Dic.Document.DocId, false)
.Take(1)
.UniqueResult;
if Assigned(lastDoc) then
Doc.DocId := lastDoc.DocId+1
else
Doc.DocId := 1;
end;
{$ENDREGION}
{$REGION 'Save document'}
// Save all items
for itm in Doc.Items do begin
itm.Header := Doc;
end;
mngr.SaveOrUpdate(Doc);
mngr.Flush(Doc);
Result.Id := Doc.Id.ToString;
except
on E: Exception do begin
Result.Add(E.Message);
Result.Id := '';
end;
end;
end;
The problem
The error I get is "Project raised exception class EObjectAlreadyPersistent with message 'Cannot turn persistent object of class TProduct with id 10. The object is already in persistent context.'."
Obviously the product already existed, I just wanted to link it to the TDocItem.
I checked that XDataServer.PostMode is Replicate.
I'm stuck :)
Kind regards,
m@rko