« Version 2025 r2 (release note) » : différence entre les versions
(Page créée avec « {{version2025r1}} __TOC__ ''' PREVIEW ''' ==Script== ===Vue locale=== * Paramètre de type de donnée <source lang="delphi"> Type vue1 = viewOf(ClassA) p1:TEnum(... ») |
Aucun résumé des modifications |
||
| (46 versions intermédiaires par le même utilisateur non affichées) | |||
| Ligne 1 : | Ligne 1 : | ||
{{ | {{version2025r2}} | ||
__TOC__ | __TOC__ | ||
''' | ==Langage== | ||
* Valeur par défaut de paramètre | |||
: Il est possible de définir des valeurs par défaut aux paramètres des méthodes | |||
<source lang="delphi"> | |||
MyClass = Class(TitObject) | |||
Procedure TestDeffParams; | |||
Procedure TestDefParamBool(p1:string; p2:boolean=true); | |||
Procedure TestDefParamJson(p1:string; p2:TJson=nil); | |||
Procedure TestDefParamJson2(p1:string; p2:TJson='{a:false}'); | |||
Procedure TestDefParamEnum(p1:string; p2:Integer=WFCAState_Etat2); | |||
Procedure TestDefParamMulti(p1:string; p2:string='a'; p3:string='b'); | |||
Function TestDefParamOne(p1:string='a'):string; | |||
Function TestDefParamFunc(p1:string='a'):string; | |||
end; | |||
Procedure MyClass.TestDefParamJson(p1:string; p2:TJson=nil); | |||
var json:TJson; | |||
begin | |||
json := TJsonStruct.Create('{}'); | |||
// | |||
// use Assigned insted of p2<>nil | |||
// | |||
if assigned(p2) then json.addStruct('p2',p2); | |||
end; | |||
Procedure MyClass.TestDeffParams; | |||
var V:string; | |||
begin | |||
V := TestDefParamFunc('c'); | |||
ShowMessage(V); | |||
TestDefParamOne; | |||
TestDefParamOne(); | |||
TestDefParamOne('x'); | |||
TestDefParamMulti('a'); | |||
TestDefParamMulti('a','1'); | |||
TestDefParamMulti('a','1','2'); | |||
TestDefParamBool('a'); | |||
TestDefParamBool('a',false); | |||
TestDefParamBool('a',true); | |||
TestDefParamJson2('b'); | |||
TestDefParamJson2('b','{a:true}'); | |||
TestDefParamEnum('c'); | |||
TestDefParamEnum('c',WFCAState_Final); | |||
end; | |||
</source> | |||
* Paramètre de type classe | |||
: Les paramètres de type classe peuvent être passé directement | |||
<source lang="delphi"> | |||
Type | |||
MyClass1 = class | |||
class procedure foo(rg:TRegClass); | |||
end; | |||
MyClass2 = class | |||
.... | |||
end; | |||
MyClass3 = class | |||
procedure oldbar(); | |||
procedure newbar(); | |||
end; | |||
class procedure MyClass1.foo(rg:TRegClass); | |||
begin | |||
// => MyClass2 | |||
showMessage(rg.aClassName); | |||
end; | |||
procedure MyClass3.oldbar(); | |||
var rg:TRegClass; | |||
begin | |||
ModelManager.FindClass('MyClass2'); | |||
myClass1.foo(rg); | |||
end; | |||
procedure MyClass3.newbar(); | |||
begin | |||
myClass1.foo(MyClass2); | |||
end; | |||
</source> | |||
==Json== | |||
* Opérateur In | |||
: Un json de type structure supporte l'opérateur In | |||
<source lang="delphi"> | |||
Procedure TestJson; | |||
function _foo(p:TJson):boolean; | |||
begin | |||
Result := false; | |||
if 'a' in p then | |||
begin | |||
Result := True; | |||
end; | |||
end; | |||
var js:TJson; | |||
begin | |||
js := TJson.Create('{a:true}'); | |||
if _foo(js) then showMessage('ok') else showMessage('nok'); | |||
end; | |||
</source> | |||
* Getter et Setter | |||
: Un json de type structure supporte l'accès direct aux valeur des membres | |||
<source lang="delphi"> | |||
Procedure TestJson; | |||
function _foo(p:TJson):boolean; | |||
begin | |||
Result := false; | |||
if 'a' in p then | |||
begin | |||
Result := p['a']; | |||
end; | |||
end; | |||
var js:TJson; | |||
begin | |||
js := TJson.Create('{a:true}'); | |||
js['b'] := False; | |||
js['a'] := not js['b']; | |||
if _foo(js) then showMessage('ok') else showMessage('nok'); | |||
end; | |||
</source> | |||
* Constructeur implicite | |||
: Un paramètre TJson peut être instancié à partir d'une chaine de caractère | |||
<source lang="delphi"> | |||
Procedure TestJson; | |||
function _foo(p:TJson):boolean; | |||
begin | |||
Result := false; | |||
if 'a' in p then | |||
begin | |||
Result := p['a']; | |||
end; | |||
end; | |||
begin | |||
if _foo('{a:true}') then showMessage('ok') else showMessage('nok'); | |||
end; | |||
</source> | |||
{{tip|La chaine doit être une constante, l'instanciation à partir d'une chaîne construite dynamiquement ne marche pas : | |||
<source lang="delphi"> | |||
Procedure TestJson; | |||
function _foo(p:TJson):string; | |||
begin | |||
Result := false; | |||
if 'a' in p then | |||
begin | |||
Result := p['a']; | |||
end; | |||
end; | |||
var v:string; | |||
begin | |||
v := 'une chaine'; | |||
if _foo('{a:"'+uneChaine+'"}')<>'' then showMessage('ok') else showMessage('nok'); // don't work ! | |||
end; | |||
</source> | |||
}} | |||
* Enumérateurs | |||
: Un json de type strutucture supporte l'énumérateur sur les clés | |||
: Un json de type tableau supporte l'énumérateur sur les éléments | |||
<source lang="delphi"> | |||
//Procedure TestJson; | |||
procedure _enumValues(p:TJson); | |||
var i:Integer; V:Variant; | |||
begin | |||
forEach V in p index i do | |||
begin | |||
showMessageFmt('%d:%s',[i,V]); | |||
end; | |||
end; | |||
procedure _enumKeys(p:TJson); | |||
var i:Integer; Key,Keys,stag:string; | |||
begin | |||
Keys := ''; stag := ''; | |||
forEach key in p index i do | |||
begin | |||
Keys := Keys+stag+inttostr(i)+':'+key; | |||
stag := ','; | |||
end; | |||
showMessage(Keys); | |||
end; | |||
begin | |||
_enumKeys('{a:true, b:false}'); | |||
_enumValues('[{a:true, b:false},{a:false, b:true}]'); | |||
end; | |||
</source> | |||
==Modèle== | |||
===Classes=== | |||
* Méthode AllocOID | |||
<source lang="delphi">class function AllocOID:TOID;</source> | |||
* Alloue un oid de la classe | |||
: Peut être utile dans les tests unitaires | |||
* Méthode ToJson() | |||
<source lang="delphi">procedure ToJson(SA:variant);</source> | |||
* Sérialize l'objet en json | |||
: SA peut être un TJsonArray ou un TJsonStruct | |||
===Classes SQL=== | |||
* Options de rôle : NoRefIndex | |||
* Options de rôle : NoForeignKey | |||
==Script== | ==Script== | ||
===Trace=== | |||
<source lang="delphi">procedure dbgClear();</source> | |||
: Vide la trace | |||
<source lang="delphi">procedure dbgEnable(value:boolean);</source> | |||
: Active / désactive la trace | |||
===Vue locale=== | ===Vue locale=== | ||
* Une vue locale peut contenir des attributs "oidXXX" sans définir le rôle | |||
'''Exemple:''' | |||
<source lang="delphi"> | |||
Type | |||
vue1 = viewOf(ClassA) | |||
p1:TEnum(enumName) = ...; | |||
oidRef:TOID = oidrefB; | |||
.. | |||
idRefB:TOID = oidrefB notInSelect; | |||
[ (idRefB=%ArgRefB) and ....] | |||
end; | |||
</source> | |||
* Une vue locale peut contenir des attributs non mappés dans la définition, ces attributs peuvent ensuite être mappés dynamiquement par le selecteur en utilisant addColumn() | |||
'''Exemple:''' | |||
<source lang="delphi"> | |||
Type | |||
vue1 = viewOf(ClassA) | |||
ACount:Integer = count(oid) | |||
oidRef:TOID; | |||
codeRef:string; | |||
libelleRef:string; | |||
.. | |||
[ ...] | |||
end; | |||
var sel:TSelector; | |||
begin | |||
sel := vue1.createSelector(); | |||
case iGroupBy of | |||
'refB': | |||
begin | |||
sel.AddColumn('oidrefB','oidRef'); | |||
sel.AddColumn('refB.code','codeRef'); | |||
sel.AddColumn('refB.Caption','libelleRef'); | |||
end; | |||
'refC': | |||
begin | |||
sel.AddColumn('oidrefC','oidRef'); | |||
sel.AddColumn('refC.code','codeRef'); | |||
sel.AddColumn('refC.Caption','libelleRef'); | |||
end; | |||
end; | |||
end; | |||
</source> | |||
* Paramètre de type de donnée | * Paramètre de type de donnée | ||
| Ligne 14 : | Ligne 310 : | ||
vue1 = viewOf(ClassA) | vue1 = viewOf(ClassA) | ||
p1:TEnum(enumName) = ...; | p1:TEnum(enumName) = ...; | ||
end; | |||
</source> | |||
* Qualifier d'attribut NotInGroupBy | |||
<source lang="delphi"> | |||
Type | |||
vue1 = viewOf(ClassA) | |||
p1:string = expression('...') notInGroupBy; | |||
end; | end; | ||
</source> | </source> | ||
| Ligne 27 : | Ligne 332 : | ||
vue2 = viewOf(vue1) | vue2 = viewOf(vue1) | ||
p2:string = ...; | |||
[inherited] | [inherited and (...)] | ||
end; | |||
</source> | |||
'''Exemple:''' | |||
<source lang="delphi"> | |||
//function GetSelector(iGroupBy:string; iFilter:TJsonArray):TSelector; | |||
Type | |||
// défini une classe de base avec tous les filtres | |||
// | |||
vueEcritureLettrage = viewOf(TEcriture) | |||
lettrable:boolean = compteGeneral.lettrable notInSelect; | |||
idEtablissement:TOID = piece.oidEtablissement notInSelect; | |||
idCompteGeneral:TOID = oidCompteGeneral notInSelect; | |||
idRoleTiers:TOID = oidroleTiers notInSelect; | |||
[(lettrable=true) | |||
and ((oidLettrageEcriture='') or (dateLettrage=0)) | |||
and (typeEcriture<>0) | |||
and (piece.lot.origineLot<>0) | |||
and (eDate>=%ArgDateInf) | |||
and (eDate<=%ArgDateSup) | |||
and (idEtablissement=%ArgEtablissement) | |||
and (idCompteGeneral=%ArgCompteGeneral) | |||
and (idRoleTiers=%ArgRoleTiers) | |||
] | |||
end; | end; | ||
// Hérite de tous les filtres | |||
// | |||
vueEcritureLettrageGroupBy = viewOf(vueEcritureLettrage) | |||
dateMin:TDatetime = min(eDate); | |||
dateMax:TDatetime = max(eDate); | |||
ACount:Integer = count(oid); | |||
credit:Currency = sum('credit:TCValue'); | |||
debit:Currency = sum('debit:TCValue'); | |||
solde:Currency = sumDiff(debit,credit); | |||
[inherited] | |||
end; | |||
begin | |||
Result := vueLettrageGroupBy.CreateSelector('','',True,[]); | |||
end; | |||
</source> | </source> | ||
* Scope de vue locale | * Scope de vue locale | ||
Une vue locale peut être référencée en dehors de la méthode où elle est définie. | |||
<source lang="delphi"> | <source lang="delphi"> | ||
| Ligne 47 : | Ligne 395 : | ||
Type | Type | ||
vue2 = viewOf(class1.foo.vue1) | vue2 = viewOf(class1.foo.vue1) | ||
p2:string = ...; | |||
end; | end; | ||
begin | begin | ||
| Ligne 55 : | Ligne 403 : | ||
* Expression Exists() | * Expression Exists() | ||
Une expression existe peut être utilisée dans les filtres comme une valeur logique | |||
{{tip|Une expression Exists() est beaucoup plus rapide qu'un "Count<>0"} | |||
<source lang="delphi"> | <source lang="delphi"> | ||
| Ligne 68 : | Ligne 420 : | ||
end; | end; | ||
</source> | </source> | ||
* Expression de Sous requête | |||
Une expression peut être définie par une sous requête | |||
<source lang="delphi"> | |||
Type | |||
VueTauxADate = ViewOf(TTauxADate) | |||
idTVA : TOid = oidTVA; | |||
tDate : Date = tDate; | |||
taux : float = taux; | |||
end; | |||
vueMontantTVA = viewOf(TEcriture) | |||
dateEcriture:TDatetime=eDate notInSelect; | |||
oidTVA:TOID = ProfilTVA.oidTVA notInSelect; | |||
oidPiece:TOID = oidPiece; | |||
montantTVAReel:Currency = vueTauxADate.select('taux * self.montant_TCValue /100','(tDate<=self.dateEcriture)and(idTVA=self.oidTVA)','',True,[]); | |||
montantTVAReel_CodeDevise:string = montantTVAReel:CodeDevise; | |||
end; | |||
</source> | |||
==ToJson== | |||
Permet de sérialiser l'objet ou l'ensemble d'objets au format json compatible avec les tables du client React | |||
<pre> procedure TObject.ToJson(SA:TJsonArray);</pre> | |||
<pre> procedure TObject.ToJsonEx(SA:TJsonArray; iOptions:TSerializeJsonOptions);</pre> | |||
<pre> procedure TSelector.ToJson(SA:TJsonArray);</pre> | |||
<pre> procedure TSelector.ToJsonEx(SA:TJsonArray; iOptions:TSerializeJsonOptions);</pre> | |||
<pre> procedure TRole.ToJson(SA:TJsonArray);</pre> | |||
TSerializeJsonOptions : | |||
* sjoIdAsGuid | |||
: Le membre id de la sérialisation sera un GUID | |||
* sjoIdAsOid | |||
: Le membre id de la sérialisation sera l'OID de l'objet | |||
<source lang="delphi"> | |||
//procedure GetData(SRows:TJsonArray); | |||
Type | |||
myView = viewOf(...) | |||
... | |||
end; | |||
var sel:TSelector; | |||
begin | |||
// Selector to retreive the data | |||
// | |||
sel := myView.CreateSelector('','',True,[]); | |||
sel.ToJson(SRows); | |||
end; | |||
</source> | |||
===Formats=== | |||
Le formattage de la sérialisation des propriétés peut être controllé par les propriétés du type | |||
<pre> | |||
Type | |||
vue = viewOf(...) | |||
p:string(typeParam1,typeParam2,typeParam3) = x; | |||
end; | |||
</pre> | |||
{|class="wikitable" | |||
|- | |||
!Type de l'attribut | |||
!TypeParam1 | |||
!TypeParam2 | |||
!TypeParam3 | |||
!Usage | |||
|- | |||
|Currency | |||
|fmtTC | |||
| - | |||
| - | |||
|Le montant est considéré en valeur de tenue de compte | |||
|- | |||
|Currency | |||
|fmtRP | |||
| - | |||
| - | |||
|Le montant est considéré en valeur de reporting | |||
|- | |||
|String contenant un TfwParameters | |||
|fmtParameters | |||
| - | |||
| - | |||
|Valeur des paramètres | |||
|- | |||
|String contenant un TfwParameters | |||
|fmtParameter | |||
|Nom du paramètre | |||
|Valeur par défaut si le paramètre n'existe pas | |||
|Valeur du paramètre | |||
|- | |||
|String | |||
|fmtTaskCategory | |||
| - | |||
| - | |||
|Catégorie de tâche | |||
|- | |||
|oid de TdbfDocument | |||
|fmtDocumentUrl | |||
|Paramètre optionnel contenant le nom du document | |||
|Paramètre optionnel contenant une url externe | |||
|Lien sur le document | |||
|- | |||
|Datetime | |||
|fmtUTC | |||
| - | |||
| - | |||
|La date en considérée UTC et convertie en date locale | |||
|- | |||
|Integer (idOTP) | |||
|fmtClassLabel | |||
| - | |||
| - | |||
|Le libellé de la classe | |||
|- | |||
|Integer (idOTP) | |||
|fmtClassName | |||
| - | |||
| - | |||
|Le nom de la classe | |||
|} | |||
==Sélecteur== | ==Sélecteur== | ||
* lastOpeStamp, | * lastOpeStamp, lastOpeAffected, lastOpeFirstOID | ||
: Attributs mis à jour par la dernière opération assembliste. | : Attributs mis à jour par la dernière opération assembliste. | ||
* operationId, operation | |||
: Permet d'enregistrer les opérations dans la table TsqlOperation | |||
: S'applique à CopyTo() | |||
* RmvParameter() | |||
: Permet de retirer un paramètre qui a été ajouté par AddParameter() | |||
* Amélioration de CopyTo | * Amélioration de CopyTo | ||
: Permet de créer des objets à partir d'un sélecteur | : Permet de créer des objets à partir d'un sélecteur | ||
* CopyTo, Update, UpdateFrom | |||
: Fonctionne sur les classes de stéréotype SQL | |||
* InsertInto | |||
: Permet de créer une table temporaire à partir d'un sélecteur | |||
: Réalise un select ... into TEMPTABLE from ... | |||
* SourceTableName | |||
: Permet de sélectionner une table SQL comme source de l'opération | |||
: Utiliser dans les opérations ensemblistes sur des tables temporaires | |||
===TsqlOperation=== | |||
Classe SQL définie par le framework et permettant d'enregistrer les opérations du sélecteur | |||
<source lang="delphi"> | |||
TsqlOperation = Class(TsqlObject) | |||
public | |||
class procedure CleanOpe(iOpeId:string); | |||
// | |||
property action: StringS[128]; | |||
property id: SQLIdentity; | |||
property oidSourceObject: TOID; | |||
property oidTargetObject: TOID; | |||
property opeId: StringS[128]; | |||
property operation: StringS[128]; | |||
property SourceObject: Ref(roGeneric,roNotExternal,roNoForeignKey,roNoRoleIndex) of TitObject; | |||
property TargetObject: Ref(roGeneric,roNotExternal,roNoForeignKey,roNoRoleIndex) of TitObject; | |||
end; | |||
</source> | |||
* opeId, operationId | |||
: Un identifiant unique (guid) identifiant l'ensemble des opérations | |||
* opération | |||
: Nom de l'opération dans l'ensemble des opérations | |||
* action | |||
: Action de l'opération | |||
: Par exemple INSERT pour un CopyTo | |||
* oidSourceObject | |||
: identifiant de l'objet source dans l'opération | |||
: Par exemple l'objet source de la copie pour un CopyTo | |||
* oidTargetObject | |||
: identifiant de l'objet cible dans l'opération | |||
: Par exemple l'objet copié par un CopyTo | |||
'''Exemple d'utilisation:''' | |||
<source lang="delphi"> | |||
// Créer des écritures a partir des réglements | |||
// | |||
procedure _doCreateEcritureReglements(iOidPiece:string; iOpeId:string); | |||
var sel:TSelector; | |||
begin | |||
sel := vueEcritureReglement.CreateSelector('(oidBordereau=%1)','',True,[oidBordereauReglement]); | |||
sel.AddParameter('ArgBordereau',oidBordereauReglement); | |||
sel.Operation := 'EcrReg'; | |||
sel.OpeId := iOpeId; | |||
// | |||
sel.CopyTo('TEcriture',['oidpiece','eDate','sens','sensProrata','regimeTVA','typeEcriture'],[ | |||
iOidPiece, | |||
BordereauReglement.dateReglement, | |||
sens_credit, | |||
sens_credit, | |||
regimeTVA_Encaissements, | |||
typeEcriture_Brouillard | |||
]); | |||
end; | |||
Type | |||
vueUpdateReglement = viewOf(TReglement) | |||
vl:TsqlOperation = join('(opeId=%ArgOpeId) and (operation=%ArgOperation) and (oidSourceObject=self.oid)'); | |||
oidEcriture:TOID = oidEcriture; | |||
oidTargetEcriture:TOID = vl.oidTargetObject; | |||
oidBordereau:TOID = oidBordereauReglement; | |||
end; | |||
// Met à jour l'oidEcriture créée sur les réglements correspondants | |||
.. | |||
procedure _doUpdateReglementsEcriture(iOidPiece:string; iOpeId:string); | |||
var sel:TSelector; | |||
begin | |||
sel := vueUpdateReglement.CreateSelector('(oidBordereau=%1)','',True,[oidBordereauReglement]); | |||
sel.AddParameter('ArgOpeId',iOpeId); | |||
sel.AddParameter('ArgOperation','EcrReg'); | |||
// | |||
sel.Update(['oidEcriture'],['oidTargetEcriture']); | |||
end; | |||
begin | |||
aOpeId := CreateGuid; | |||
withP long transaction do | |||
begin | |||
aOidPiece := _doCreatePiece(); | |||
_doCreateEcritureReglements(aOidPiece,aOpeId); | |||
_doUpdateReglementsEcriture(aOidPice,aOpeId); | |||
... | |||
TsqlOperation.CleanOpe(aOpeId); | |||
end; | |||
end; | |||
</source> | |||
===UpdateFrom()=== | |||
<source lang="delphi"> | |||
function updateFrom(sel:TSelector; iMatchedProps:Array of string; iUpdatedProps:Array of string; iUpdatedValue:Array of variant):Integer; | |||
</source> | |||
Permet de mettre à jour une classe à partir d'un sélecteur et d'une colonne de correspondance. | |||
'''Exemple :''' | |||
<source lang="delphi"> | |||
Type | |||
// Update the temp table | |||
vueTemp = viewOf(TempLettrage) | |||
reference1:string = reference1; | |||
reference2:string = reference2; | |||
modeLettrage:Integer = modeLettrage; | |||
end; | |||
vueRef1 = viewOf(TempLettrage) | |||
//ACount:Integer = count(id); | |||
ATotal:Currency = sumSign(montant:TCValue,sens,'1'); | |||
reference1:string = reference1; | |||
[(modeLettrage=0) and (reference1<>'')] | |||
end; | |||
var selT,selG:TSelector; | |||
begin | |||
withP long transaction do | |||
begin | |||
// for updating the temp table on "match" | |||
selT := vueTemp.CreateSelector('','',True,[]); | |||
// Lettrage sur reference 1 | |||
selG := vueRef1.CreateSelector('(ATotal=0)','',True,[]); | |||
selG.useCTE := True; | |||
selT.UpdateFrom(selG,['reference1'],['modeLettrage'],[1]); | |||
end; | |||
end; | |||
</source> | |||
<pre> | |||
with CTE as ( | |||
select sum(case when t0.sens=1 then ISNULL(t0.montant_TCValue, 0) else -ISNULL(t0.montant_TCValue, 0) end) as "ATotal",t0.reference1 as "reference1" | |||
from dbo.TEMPLETTRAGE t0 WITH (NOLOCK) | |||
where ((t0.modeLettrage = 0) and (t0.reference1 IS NOT NULL)) | |||
group by t0.reference1 | |||
) | |||
merge into dbo.TEMPLETTRAGE tm0 using ( | |||
SELECT * | |||
FROM CTE | |||
Where (ATotal = 0.0000) | |||
) tm1 on (tm1.reference1=tm0.reference1) | |||
when matched then update set | |||
tm0.modeLettrage = 1 | |||
; | |||
</pre> | |||
==Opérations ensemblistes SQL== | |||
Des opérations ensemblistes utilisant des tables SQL temporaires peuvent être réalisées en utilisant l'opération InserInto du selecteur. | |||
===Table temporaire=== | |||
* TDatabase.AllocTempTable(JobId:string) | |||
: Génère un nom de table temporaire | |||
* TDatabase.DropTempTables(JobId:string) | |||
: Supprime (drop) les tables temporaires | |||
===Vue SQL locale=== | |||
Une vue SQL locale permet d'utiliser une table SQL comme source d'opération d'un sélecteur | |||
<source lang="delphi"> | |||
Type | |||
// define an interface | |||
intf = interface | |||
... | |||
end; | |||
// create a view which support the interface | |||
// will be used to create the temp table | |||
// | |||
vue = viewOf(MyClass,intf) | |||
end; | |||
// define a sql class based on the interface | |||
// | |||
sql = sqlClass(intf) | |||
end; | |||
// view on the sql class | |||
// | |||
vue2 = viewOf(sql) | |||
... | |||
end; | |||
var sel:Tselector; aJob,aTempTable:string; keepTables:boolean; | |||
begin | |||
// Alloc a temp table name | |||
// | |||
aJob := CreateGuid; | |||
aTempTable := ClassManager.DefDatabase.AllocTempTable(aJob); | |||
KeepTables := false; // for debuging | |||
try | |||
// Create a temp table from MyClass view | |||
// | |||
sel := vue.CreateSelector(...); | |||
sel.insertInto(aTempTable,[...],[...]); // we create a tempTable | |||
// Query the temp table throught the vue2 | |||
// | |||
sel := vue2.CreateSelector(...); | |||
sel.SourceTableName := aTempTable; // because we select the tempTable | |||
... | |||
finally | |||
if not KeepTables then ClassManager.DefDatabase.DropTempTables(aJob); | |||
end; | |||
end; | |||
</source> | |||
==Updater== | |||
Classe technique permettant de mettre à jour un attribut sur un ensemble d'objet. | |||
'''Exemple : Mise à jour des compteurs qui ne peuvent pas être déterminés en SQL''' | |||
<source lang="delphi"> | |||
Type | |||
// Should returns all attributes part of the counter | |||
// | |||
vueNumeroPiece = viewOf(TPiece) | |||
pDate:TDatetime = pDate; | |||
numero:TCounter = numero; | |||
end; | |||
procedure _doUpdateNumeroPiece(iOidPiece:string); | |||
var sel:TSelector; vueNP:vueNumeroPiece; upd:TUpdater; | |||
begin | |||
upd := TPiece.CreateUpdater('numero'); | |||
// | |||
sel := vueNumeroPiece.CreateSelector('(oid=%1)','',True,[iOidPiece]); | |||
forEach vueNP in sel.AsCursor do | |||
begin | |||
vueNP.numero.AllocValue; | |||
upd.AddValue(vueNP.OID,vueNP.numero.value); | |||
end; | |||
// | |||
upd.Execute; | |||
end; | |||
begin | |||
end; | |||
</source> | |||
==Interface== | |||
* [[Améliorations des contrôles d'interface (Version 11.00 2025 r2)]] | |||
[[Category: | [[Category:Version2025r2]] | ||
[[Category:Release note]] | [[Category:Release note]] | ||
Dernière version du 16 mars 2026 à 14:28
Langage
- Valeur par défaut de paramètre
- Il est possible de définir des valeurs par défaut aux paramètres des méthodes
MyClass = Class(TitObject)
Procedure TestDeffParams;
Procedure TestDefParamBool(p1:string; p2:boolean=true);
Procedure TestDefParamJson(p1:string; p2:TJson=nil);
Procedure TestDefParamJson2(p1:string; p2:TJson='{a:false}');
Procedure TestDefParamEnum(p1:string; p2:Integer=WFCAState_Etat2);
Procedure TestDefParamMulti(p1:string; p2:string='a'; p3:string='b');
Function TestDefParamOne(p1:string='a'):string;
Function TestDefParamFunc(p1:string='a'):string;
end;
Procedure MyClass.TestDefParamJson(p1:string; p2:TJson=nil);
var json:TJson;
begin
json := TJsonStruct.Create('{}');
//
// use Assigned insted of p2<>nil
//
if assigned(p2) then json.addStruct('p2',p2);
end;
Procedure MyClass.TestDeffParams;
var V:string;
begin
V := TestDefParamFunc('c');
ShowMessage(V);
TestDefParamOne;
TestDefParamOne();
TestDefParamOne('x');
TestDefParamMulti('a');
TestDefParamMulti('a','1');
TestDefParamMulti('a','1','2');
TestDefParamBool('a');
TestDefParamBool('a',false);
TestDefParamBool('a',true);
TestDefParamJson2('b');
TestDefParamJson2('b','{a:true}');
TestDefParamEnum('c');
TestDefParamEnum('c',WFCAState_Final);
end;
- Paramètre de type classe
- Les paramètres de type classe peuvent être passé directement
Type
MyClass1 = class
class procedure foo(rg:TRegClass);
end;
MyClass2 = class
....
end;
MyClass3 = class
procedure oldbar();
procedure newbar();
end;
class procedure MyClass1.foo(rg:TRegClass);
begin
// => MyClass2
showMessage(rg.aClassName);
end;
procedure MyClass3.oldbar();
var rg:TRegClass;
begin
ModelManager.FindClass('MyClass2');
myClass1.foo(rg);
end;
procedure MyClass3.newbar();
begin
myClass1.foo(MyClass2);
end;
Json
- Opérateur In
- Un json de type structure supporte l'opérateur In
Procedure TestJson;
function _foo(p:TJson):boolean;
begin
Result := false;
if 'a' in p then
begin
Result := True;
end;
end;
var js:TJson;
begin
js := TJson.Create('{a:true}');
if _foo(js) then showMessage('ok') else showMessage('nok');
end;
- Getter et Setter
- Un json de type structure supporte l'accès direct aux valeur des membres
Procedure TestJson;
function _foo(p:TJson):boolean;
begin
Result := false;
if 'a' in p then
begin
Result := p['a'];
end;
end;
var js:TJson;
begin
js := TJson.Create('{a:true}');
js['b'] := False;
js['a'] := not js['b'];
if _foo(js) then showMessage('ok') else showMessage('nok');
end;
- Constructeur implicite
- Un paramètre TJson peut être instancié à partir d'une chaine de caractère
Procedure TestJson;
function _foo(p:TJson):boolean;
begin
Result := false;
if 'a' in p then
begin
Result := p['a'];
end;
end;
begin
if _foo('{a:true}') then showMessage('ok') else showMessage('nok');
end;
- Enumérateurs
- Un json de type strutucture supporte l'énumérateur sur les clés
- Un json de type tableau supporte l'énumérateur sur les éléments
//Procedure TestJson;
procedure _enumValues(p:TJson);
var i:Integer; V:Variant;
begin
forEach V in p index i do
begin
showMessageFmt('%d:%s',[i,V]);
end;
end;
procedure _enumKeys(p:TJson);
var i:Integer; Key,Keys,stag:string;
begin
Keys := ''; stag := '';
forEach key in p index i do
begin
Keys := Keys+stag+inttostr(i)+':'+key;
stag := ',';
end;
showMessage(Keys);
end;
begin
_enumKeys('{a:true, b:false}');
_enumValues('[{a:true, b:false},{a:false, b:true}]');
end;
Modèle
Classes
- Méthode AllocOID
class function AllocOID:TOID;
- Alloue un oid de la classe
- Peut être utile dans les tests unitaires
- Méthode ToJson()
procedure ToJson(SA:variant);
- Sérialize l'objet en json
- SA peut être un TJsonArray ou un TJsonStruct
Classes SQL
- Options de rôle : NoRefIndex
- Options de rôle : NoForeignKey
Script
Trace
procedure dbgClear();
- Vide la trace
procedure dbgEnable(value:boolean);
- Active / désactive la trace
Vue locale
- Une vue locale peut contenir des attributs "oidXXX" sans définir le rôle
Exemple:
Type
vue1 = viewOf(ClassA)
p1:TEnum(enumName) = ...;
oidRef:TOID = oidrefB;
..
idRefB:TOID = oidrefB notInSelect;
[ (idRefB=%ArgRefB) and ....]
end;
- Une vue locale peut contenir des attributs non mappés dans la définition, ces attributs peuvent ensuite être mappés dynamiquement par le selecteur en utilisant addColumn()
Exemple:
Type
vue1 = viewOf(ClassA)
ACount:Integer = count(oid)
oidRef:TOID;
codeRef:string;
libelleRef:string;
..
[ ...]
end;
var sel:TSelector;
begin
sel := vue1.createSelector();
case iGroupBy of
'refB':
begin
sel.AddColumn('oidrefB','oidRef');
sel.AddColumn('refB.code','codeRef');
sel.AddColumn('refB.Caption','libelleRef');
end;
'refC':
begin
sel.AddColumn('oidrefC','oidRef');
sel.AddColumn('refC.code','codeRef');
sel.AddColumn('refC.Caption','libelleRef');
end;
end;
end;
- Paramètre de type de donnée
Type
vue1 = viewOf(ClassA)
p1:TEnum(enumName) = ...;
end;
- Qualifier d'attribut NotInGroupBy
Type
vue1 = viewOf(ClassA)
p1:string = expression('...') notInGroupBy;
end;
- Héritage de vue locale
Type
vue1 = viewOf(ClassA)
p1:string = ...;
[...]
end;
vue2 = viewOf(vue1)
p2:string = ...;
[inherited and (...)]
end;
Exemple:
//function GetSelector(iGroupBy:string; iFilter:TJsonArray):TSelector;
Type
// défini une classe de base avec tous les filtres
//
vueEcritureLettrage = viewOf(TEcriture)
lettrable:boolean = compteGeneral.lettrable notInSelect;
idEtablissement:TOID = piece.oidEtablissement notInSelect;
idCompteGeneral:TOID = oidCompteGeneral notInSelect;
idRoleTiers:TOID = oidroleTiers notInSelect;
[(lettrable=true)
and ((oidLettrageEcriture='') or (dateLettrage=0))
and (typeEcriture<>0)
and (piece.lot.origineLot<>0)
and (eDate>=%ArgDateInf)
and (eDate<=%ArgDateSup)
and (idEtablissement=%ArgEtablissement)
and (idCompteGeneral=%ArgCompteGeneral)
and (idRoleTiers=%ArgRoleTiers)
]
end;
// Hérite de tous les filtres
//
vueEcritureLettrageGroupBy = viewOf(vueEcritureLettrage)
dateMin:TDatetime = min(eDate);
dateMax:TDatetime = max(eDate);
ACount:Integer = count(oid);
credit:Currency = sum('credit:TCValue');
debit:Currency = sum('debit:TCValue');
solde:Currency = sumDiff(debit,credit);
[inherited]
end;
begin
Result := vueLettrageGroupBy.CreateSelector('','',True,[]);
end;
- Scope de vue locale
Une vue locale peut être référencée en dehors de la méthode où elle est définie.
procedure Class1.foo;
Type
vue1 = viewOf(ClassA)
p1:string = ...;
end;
begin
...
end;
procedure Class2.bar;
Type
vue2 = viewOf(class1.foo.vue1)
p2:string = ...;
end;
begin
...
end;
- Expression Exists()
Une expression existe peut être utilisée dans les filtres comme une valeur logique
{{tip|Une expression Exists() est beaucoup plus rapide qu'un "Count<>0"}
Type
vue1 = viewOf(ClassA)
id:string = ...;
end;
vue2 = viewOf(ClassB)
id:string = ...;
bb:boolean = vue1.Exists('(id=self.id)',True,[]) notInSelect;
[(bb=true) and (....)]
end;
- Expression de Sous requête
Une expression peut être définie par une sous requête
Type
VueTauxADate = ViewOf(TTauxADate)
idTVA : TOid = oidTVA;
tDate : Date = tDate;
taux : float = taux;
end;
vueMontantTVA = viewOf(TEcriture)
dateEcriture:TDatetime=eDate notInSelect;
oidTVA:TOID = ProfilTVA.oidTVA notInSelect;
oidPiece:TOID = oidPiece;
montantTVAReel:Currency = vueTauxADate.select('taux * self.montant_TCValue /100','(tDate<=self.dateEcriture)and(idTVA=self.oidTVA)','',True,[]);
montantTVAReel_CodeDevise:string = montantTVAReel:CodeDevise;
end;
ToJson
Permet de sérialiser l'objet ou l'ensemble d'objets au format json compatible avec les tables du client React
procedure TObject.ToJson(SA:TJsonArray);
procedure TObject.ToJsonEx(SA:TJsonArray; iOptions:TSerializeJsonOptions);
procedure TSelector.ToJson(SA:TJsonArray);
procedure TSelector.ToJsonEx(SA:TJsonArray; iOptions:TSerializeJsonOptions);
procedure TRole.ToJson(SA:TJsonArray);
TSerializeJsonOptions :
- sjoIdAsGuid
- Le membre id de la sérialisation sera un GUID
- sjoIdAsOid
- Le membre id de la sérialisation sera l'OID de l'objet
//procedure GetData(SRows:TJsonArray);
Type
myView = viewOf(...)
...
end;
var sel:TSelector;
begin
// Selector to retreive the data
//
sel := myView.CreateSelector('','',True,[]);
sel.ToJson(SRows);
end;
Formats
Le formattage de la sérialisation des propriétés peut être controllé par les propriétés du type
Type
vue = viewOf(...)
p:string(typeParam1,typeParam2,typeParam3) = x;
end;
| Type de l'attribut | TypeParam1 | TypeParam2 | TypeParam3 | Usage |
|---|---|---|---|---|
| Currency | fmtTC | - | - | Le montant est considéré en valeur de tenue de compte |
| Currency | fmtRP | - | - | Le montant est considéré en valeur de reporting |
| String contenant un TfwParameters | fmtParameters | - | - | Valeur des paramètres |
| String contenant un TfwParameters | fmtParameter | Nom du paramètre | Valeur par défaut si le paramètre n'existe pas | Valeur du paramètre |
| String | fmtTaskCategory | - | - | Catégorie de tâche |
| oid de TdbfDocument | fmtDocumentUrl | Paramètre optionnel contenant le nom du document | Paramètre optionnel contenant une url externe | Lien sur le document |
| Datetime | fmtUTC | - | - | La date en considérée UTC et convertie en date locale |
| Integer (idOTP) | fmtClassLabel | - | - | Le libellé de la classe |
| Integer (idOTP) | fmtClassName | - | - | Le nom de la classe |
Sélecteur
- lastOpeStamp, lastOpeAffected, lastOpeFirstOID
- Attributs mis à jour par la dernière opération assembliste.
- operationId, operation
- Permet d'enregistrer les opérations dans la table TsqlOperation
- S'applique à CopyTo()
- RmvParameter()
- Permet de retirer un paramètre qui a été ajouté par AddParameter()
- Amélioration de CopyTo
- Permet de créer des objets à partir d'un sélecteur
- CopyTo, Update, UpdateFrom
- Fonctionne sur les classes de stéréotype SQL
- InsertInto
- Permet de créer une table temporaire à partir d'un sélecteur
- Réalise un select ... into TEMPTABLE from ...
- SourceTableName
- Permet de sélectionner une table SQL comme source de l'opération
- Utiliser dans les opérations ensemblistes sur des tables temporaires
TsqlOperation
Classe SQL définie par le framework et permettant d'enregistrer les opérations du sélecteur
TsqlOperation = Class(TsqlObject)
public
class procedure CleanOpe(iOpeId:string);
//
property action: StringS[128];
property id: SQLIdentity;
property oidSourceObject: TOID;
property oidTargetObject: TOID;
property opeId: StringS[128];
property operation: StringS[128];
property SourceObject: Ref(roGeneric,roNotExternal,roNoForeignKey,roNoRoleIndex) of TitObject;
property TargetObject: Ref(roGeneric,roNotExternal,roNoForeignKey,roNoRoleIndex) of TitObject;
end;
- opeId, operationId
- Un identifiant unique (guid) identifiant l'ensemble des opérations
- opération
- Nom de l'opération dans l'ensemble des opérations
- action
- Action de l'opération
- Par exemple INSERT pour un CopyTo
- oidSourceObject
- identifiant de l'objet source dans l'opération
- Par exemple l'objet source de la copie pour un CopyTo
- oidTargetObject
- identifiant de l'objet cible dans l'opération
- Par exemple l'objet copié par un CopyTo
Exemple d'utilisation:
// Créer des écritures a partir des réglements
//
procedure _doCreateEcritureReglements(iOidPiece:string; iOpeId:string);
var sel:TSelector;
begin
sel := vueEcritureReglement.CreateSelector('(oidBordereau=%1)','',True,[oidBordereauReglement]);
sel.AddParameter('ArgBordereau',oidBordereauReglement);
sel.Operation := 'EcrReg';
sel.OpeId := iOpeId;
//
sel.CopyTo('TEcriture',['oidpiece','eDate','sens','sensProrata','regimeTVA','typeEcriture'],[
iOidPiece,
BordereauReglement.dateReglement,
sens_credit,
sens_credit,
regimeTVA_Encaissements,
typeEcriture_Brouillard
]);
end;
Type
vueUpdateReglement = viewOf(TReglement)
vl:TsqlOperation = join('(opeId=%ArgOpeId) and (operation=%ArgOperation) and (oidSourceObject=self.oid)');
oidEcriture:TOID = oidEcriture;
oidTargetEcriture:TOID = vl.oidTargetObject;
oidBordereau:TOID = oidBordereauReglement;
end;
// Met à jour l'oidEcriture créée sur les réglements correspondants
..
procedure _doUpdateReglementsEcriture(iOidPiece:string; iOpeId:string);
var sel:TSelector;
begin
sel := vueUpdateReglement.CreateSelector('(oidBordereau=%1)','',True,[oidBordereauReglement]);
sel.AddParameter('ArgOpeId',iOpeId);
sel.AddParameter('ArgOperation','EcrReg');
//
sel.Update(['oidEcriture'],['oidTargetEcriture']);
end;
begin
aOpeId := CreateGuid;
withP long transaction do
begin
aOidPiece := _doCreatePiece();
_doCreateEcritureReglements(aOidPiece,aOpeId);
_doUpdateReglementsEcriture(aOidPice,aOpeId);
...
TsqlOperation.CleanOpe(aOpeId);
end;
end;
UpdateFrom()
function updateFrom(sel:TSelector; iMatchedProps:Array of string; iUpdatedProps:Array of string; iUpdatedValue:Array of variant):Integer;
Permet de mettre à jour une classe à partir d'un sélecteur et d'une colonne de correspondance.
Exemple :
Type
// Update the temp table
vueTemp = viewOf(TempLettrage)
reference1:string = reference1;
reference2:string = reference2;
modeLettrage:Integer = modeLettrage;
end;
vueRef1 = viewOf(TempLettrage)
//ACount:Integer = count(id);
ATotal:Currency = sumSign(montant:TCValue,sens,'1');
reference1:string = reference1;
[(modeLettrage=0) and (reference1<>'')]
end;
var selT,selG:TSelector;
begin
withP long transaction do
begin
// for updating the temp table on "match"
selT := vueTemp.CreateSelector('','',True,[]);
// Lettrage sur reference 1
selG := vueRef1.CreateSelector('(ATotal=0)','',True,[]);
selG.useCTE := True;
selT.UpdateFrom(selG,['reference1'],['modeLettrage'],[1]);
end;
end;
with CTE as ( select sum(case when t0.sens=1 then ISNULL(t0.montant_TCValue, 0) else -ISNULL(t0.montant_TCValue, 0) end) as "ATotal",t0.reference1 as "reference1" from dbo.TEMPLETTRAGE t0 WITH (NOLOCK) where ((t0.modeLettrage = 0) and (t0.reference1 IS NOT NULL)) group by t0.reference1 ) merge into dbo.TEMPLETTRAGE tm0 using ( SELECT * FROM CTE Where (ATotal = 0.0000) ) tm1 on (tm1.reference1=tm0.reference1) when matched then update set tm0.modeLettrage = 1 ;
Opérations ensemblistes SQL
Des opérations ensemblistes utilisant des tables SQL temporaires peuvent être réalisées en utilisant l'opération InserInto du selecteur.
Table temporaire
- TDatabase.AllocTempTable(JobId:string)
- Génère un nom de table temporaire
- TDatabase.DropTempTables(JobId:string)
- Supprime (drop) les tables temporaires
Vue SQL locale
Une vue SQL locale permet d'utiliser une table SQL comme source d'opération d'un sélecteur
Type
// define an interface
intf = interface
...
end;
// create a view which support the interface
// will be used to create the temp table
//
vue = viewOf(MyClass,intf)
end;
// define a sql class based on the interface
//
sql = sqlClass(intf)
end;
// view on the sql class
//
vue2 = viewOf(sql)
...
end;
var sel:Tselector; aJob,aTempTable:string; keepTables:boolean;
begin
// Alloc a temp table name
//
aJob := CreateGuid;
aTempTable := ClassManager.DefDatabase.AllocTempTable(aJob);
KeepTables := false; // for debuging
try
// Create a temp table from MyClass view
//
sel := vue.CreateSelector(...);
sel.insertInto(aTempTable,[...],[...]); // we create a tempTable
// Query the temp table throught the vue2
//
sel := vue2.CreateSelector(...);
sel.SourceTableName := aTempTable; // because we select the tempTable
...
finally
if not KeepTables then ClassManager.DefDatabase.DropTempTables(aJob);
end;
end;
Updater
Classe technique permettant de mettre à jour un attribut sur un ensemble d'objet.
Exemple : Mise à jour des compteurs qui ne peuvent pas être déterminés en SQL
Type
// Should returns all attributes part of the counter
//
vueNumeroPiece = viewOf(TPiece)
pDate:TDatetime = pDate;
numero:TCounter = numero;
end;
procedure _doUpdateNumeroPiece(iOidPiece:string);
var sel:TSelector; vueNP:vueNumeroPiece; upd:TUpdater;
begin
upd := TPiece.CreateUpdater('numero');
//
sel := vueNumeroPiece.CreateSelector('(oid=%1)','',True,[iOidPiece]);
forEach vueNP in sel.AsCursor do
begin
vueNP.numero.AllocValue;
upd.AddValue(vueNP.OID,vueNP.numero.value);
end;
//
upd.Execute;
end;
begin
end;