В настоящий момент я внедряю проект, реализованный (почти) на Bold. Параллельно добавляются некоторые вкусности и полезности, и, естественно, устраняются багги. Одной из таких полезностей является копирование объектов. Что я имею в виду? Предположим, имеется накладная, содержащая неоторые товары. Количество и стоимость товара являются атрибутами класса-ассоциации. Я именую такой класс - расшифровка накладной. Процесс формирования накладной занимает определенное время (подбор товара, указание цены и количества и т.д.). Достаточно часто возникает необходимость создания типовых накладных. С точки зрения пользователя, в этом случае, значительно удобнее сделать копию имеющейся накладной, чем создавать новую «с нуля». Что должно произойти с технической точки зрения?
Создается новый объект – экземпляр класса «накладная»;
Устанавливаются связь нового объекта с теми товарами, которые ассоциированы с копируемой накладной;
Ищутся соответсвующие экземпляры класса –ассоциации и копируются их атрибуты.
Здесь очень важно правильно найти соответсвующие расшифровки накладных. Если в исходной накладной проводится два процессора и один винчестер, то в копии должно быть именно два процессора и винчестер, а не наоборот.
Почему задача должна решаться именно так? Мы не можем создать класс ассоциацию обычным методом. Он создается автоматически после связывания двух объектов. Возможно, было бы удобнее, создавать экземпляр класса –ассоциации, так как создаются экземпляры обычных классов, и это бы приводило к автоматическому связыванию ассоциацией соответсвующих объектов, но так не происходит. Функции TBoldCopyAndClone.BoldCopy и TBoldCopyAndClone.BoldClone также не справляются с задачей.
В принципе, вышеописанная задача достаточно типична. И я решил написать две подпрограммы, которые можно использовать в подобной ситуации без модификаций.
Вот их текст:
function TfClientCard.LocateAssObject(AssClName:string;
frstObj, secObj: TBoldObject): TBoldElement;
var
Expr: string;
brL: TBoldReferenceHandle;
BOV: TBoldOCLVariables;
CI: TBoldVariableTuple;
begin
try
brl:=TBoldReferenceHandle.Create(self);
brl.StaticSystemHandle:= DM.bsh;
brl.StaticValueTypeName:=secObj.BoldClassTypeInfo.ExpressionName;
brl.Value:= secObj as TBoldElement;
BOV:=TBoldOCLVariables.Create(self);
CI:=TBoldVariableTuple(BOV.Variables.Add);
CI.VariableName:='vNewObj';
CI.BoldHandle:=brl;
Expr:='self.'+LowerCase(AssClName)+
'->select('+LowerCase(secObj.BoldClassTypeInfo.ExpressionName)+'=vNewObj)->first';
result:=frstObj.EvaluateExpressionAsDirectElement(Expr,BOV.VariableList);
finally
bov.Free;
brl.Free;
end;
end;
procedure TfClientCard.CopyAssociations(SourceObj, DistObj: TBoldObject;
AssClassName, RoleName: string);
var
i: integer;
AssObjRel: TBoldObject;
AssObjectDist, AssObjectSource: TBoldObject;
begin
if Pos('List',SourceObj.BoldMemberByExpressionName[RoleName].ClassName)<>0 then
begin
if DistObj.ClassName=SourceObj.ClassName then
begin
for i := 0 to (SourceObj.BoldMemberByExpressionName[RoleName]
as TBoldObjectList).Count-1 do
begin
if Assigned((SourceObj.BoldMemberByExpressionName[RoleName]
as TBoldObjectList)[i] as TBoldObject) then
begin
AssObjRel:=(SourceObj.BoldMemberByExpressionName[RoleName]
as TBoldObjectList)[i] as TBoldObject;
(DistObj.BoldMemberByExpressionName[RoleName] as TBoldObjectList).Add(AssObjRel);
AssObjectDist:=LocateAssObject(AssClassName,DistObj, AssObjRel) as TBoldObject;
AssObjectSource:=LocateAssObject(AssClassName,SourceObj, AssObjRel) as TBoldObject;
TBoldCopyAndClone.BoldCopy(AssObjectDist,AssObjectSource,bcmAttributes,true);
end;
end;
end;
end
else ShowMessage('Ассоциация не множественная');
end;
end.