Vue locale (langage)
(→Opérateur portant sur un type numérique) |
(→Expression SQL) |
||
(24 révisions intermédiaires par un utilisateur sont masquées) | |||
Ligne 314 : | Ligne 314 : | ||
</source> | </source> | ||
− | ====Vue avec jointure==== | + | ====Vue avec jointure sur une classe==== |
<pre> | <pre> | ||
Ligne 341 : | Ligne 341 : | ||
|} | |} | ||
− | La clause Where peut être | + | La clause Where peut être exprimée avec les préfixes : |
{|class="wikitable" | {|class="wikitable" | ||
Ligne 350 : | Ligne 350 : | ||
|? | |? | ||
|Préfixe de la classe Join | |Préfixe de la classe Join | ||
+ | |- | ||
+ | |xx | ||
+ | |alias d'une jointure de classe | ||
|} | |} | ||
+ | {{tip|Il est possible de créer un produit cartésien entre deux classes en utilisant une jointure avec une clause where toujours vraie. }} | ||
+ | |||
+ | {{tip|Les jointures seront générées dans l'ordre de leur déclaration dans la vue. }} | ||
<source lang="delphi"> | <source lang="delphi"> | ||
Ligne 407 : | Ligne 413 : | ||
* ValidationEtat.EtatPossible.EtatMetier est le chemin issu de la classe jointe | * ValidationEtat.EtatPossible.EtatMetier est le chemin issu de la classe jointe | ||
* EtatNF est le chemin issu de la classe de la vue. | * EtatNF est le chemin issu de la classe de la vue. | ||
+ | |||
+ | |||
+ | '''Exemple, vue locale avec produit cartésien, jointure par clause where et sous requêtes''' | ||
+ | |||
+ | <source lang="delphi"> | ||
+ | //procedure RubriqueParExerciceDetail; | ||
+ | Type | ||
+ | vueSolde = viewof(TCumulPeriodeCompte) | ||
+ | codeCompte:string = CompteGeneral.codeCompte; | ||
+ | datePeriode:TDatetime = Periode.dateDebut; | ||
+ | value:Currency = sumDiff(debitTenue,creditTenue); | ||
+ | oidExercice:TOID = Periode.oidexercice; | ||
+ | [(typeLot=1)] | ||
+ | end; | ||
+ | |||
+ | vueSelection = viewOf(TSelectionCompte) | ||
+ | vc:TCompteGeneral = join('(codeCompte>=self.compteInferieur) and (codeCompte<=self.compteSuperieur)'); | ||
+ | vp:TPeriode = join('(1=1)'); | ||
+ | ve:TExercice = join(oid,vp.oidexercice); | ||
+ | ve1:TExercice = join('(?.dateDebut = DateAdd(dpyear,ve.dateDebut,-1))'); | ||
+ | // | ||
+ | idCompteGeneral:TOID = vc.oid primary; | ||
+ | idRubrique:TOID = oidRubriqueCompte primary; | ||
+ | idPeriode:TOID = vp.oid primary; | ||
+ | idExercice:TOID = vp.oidexercice; | ||
+ | idExerciceN1:TOID = ve1.oid; | ||
+ | // | ||
+ | codeRubrique:string = RubriqueCompte.code orderby; | ||
+ | libelleRubrique:string = RubriqueCompte.Caption; | ||
+ | codeCompte:string = vc.codeCompte orderby; | ||
+ | libelleCompte:string = vc.Caption; | ||
+ | libellePeriode:string = vp.Caption; | ||
+ | // | ||
+ | datePeriode:TDatetime = vp.dateDebut orderby desc; | ||
+ | year:Integer = year(vp.dateDebut); | ||
+ | month:Integer = month(vp.dateDebut); | ||
+ | valueN0:currency = VueSolde.select('value','(oidExercice=self.idExercice) and (codeCompte=self.codeCompte) and (datePeriode<=self.datePeriode)','',true,[]); | ||
+ | valueN1:currency = VueSolde.select('value','(oidExercice=self.idExerciceN1) and (codeCompte=self.codeCompte) and (datePeriode<=DateAdd(dpYear,self.datePeriode,-1))','',true,[]); | ||
+ | end; | ||
+ | |||
+ | var Sel:TSelector; inst:vueSelection; S,stag:string; | ||
+ | begin | ||
+ | Sel := vueSelection.CreateSelector('(codeRubrique=%1) and (year=2022) and (month=3)','',True,['SIG.L02']); | ||
+ | |||
+ | S := ''; stag := ''; | ||
+ | forEach inst in Sel.AsCursor do | ||
+ | begin | ||
+ | S := S+stag+inst.codeCompte; | ||
+ | stag := ','; | ||
+ | end; | ||
+ | showMessage(S); | ||
+ | end; | ||
+ | </source> | ||
+ | |||
+ | {{tip|Notez l'opérateur SQL DateAdd() qui peut être utilisé dans la partie littérale d'une expression}} | ||
====Vue avec jointures liées==== | ====Vue avec jointures liées==== | ||
Ligne 430 : | Ligne 491 : | ||
* La coincidence des deux jointures est réalisée par le clause where (aId1=aId2) | * La coincidence des deux jointures est réalisée par le clause where (aId1=aId2) | ||
* gcv est une jointure sur le tuple défini par vp1 et vp2 | * gcv est une jointure sur le tuple défini par vp1 et vp2 | ||
+ | |||
+ | ====Jointure avec filtre idOTP==== | ||
+ | |||
+ | Utilisez la fonction littérale OTP() pour filtrer sur la valeur de idOTP | ||
+ | |||
+ | Exemple : | ||
+ | |||
+ | <source lang="delphi"> | ||
+ | Type | ||
+ | vueSoldeClient = viewOf(TCumulPeriodeAuxiliaire) | ||
+ | vnc:TNormeComptable = join(oid,oidnormeComptable); | ||
+ | van:TApprocheNorme = join(oidTNormeComptable,vnc.oid); | ||
+ | vac:TApprocheComptable = join(oid,van.oidTApprocheComptable); | ||
+ | vrt:TRoleTiers = join(oid,oidroleTiers,'(?.idOTP = OTP(''TClient''))'); | ||
+ | codeApproche:string = vac.code; | ||
+ | idTiers:TOID = vrt.oidTiers; | ||
+ | solde:Currency = sumDiff(debitTenue,creditTenue); | ||
+ | [(typeLot=1) and (codeApproche='NAT')] | ||
+ | end; | ||
+ | </source> | ||
====Vue avec sous requêtes==== | ====Vue avec sous requêtes==== | ||
Ligne 485 : | Ligne 566 : | ||
Vue1.Select('sub1','(id1=self.id2)','',true,[]) | Vue1.Select('sub1','(id1=self.id2)','',true,[]) | ||
]); | ]); | ||
+ | // | ||
+ | ... | ||
+ | end; | ||
+ | </source> | ||
+ | |||
+ | '''Avec des paramètres :''' | ||
+ | |||
+ | Il est possible de paramétrer une sous requête en utilisant les paramètres de la requête principale : | ||
+ | |||
+ | <source lang="delphi"> | ||
+ | Type | ||
+ | Vue1 = viewOf(MyClass) | ||
+ | sub1:TMoney = sum(...); | ||
+ | id1:TOID = ....; | ||
+ | col1:string = ...; | ||
+ | col2:Integer = ...; | ||
+ | .... | ||
+ | end; | ||
+ | |||
+ | Vue2 = viewOf(MyClass) | ||
+ | sum1:TMoney = sum(...); | ||
+ | sum2:TMoney = Vue1.Select('sub1','(id1=self.id2) and (col=%1) and (col2=%2)','',true,[]); | ||
+ | id2:TOID = ...; | ||
+ | .... | ||
+ | end; | ||
+ | |||
+ | var sel:TSelector; | ||
+ | begin | ||
+ | sel := Vue2.CreateSelector('','',true,['valueCol1',1,....]); | ||
// | // | ||
... | ... | ||
Ligne 611 : | Ligne 721 : | ||
|over | |over | ||
|L'attribut est généré par rapport à la requête CTE | |L'attribut est généré par rapport à la requête CTE | ||
+ | |- | ||
+ | |primary (*) | ||
+ | |L'attribut fera partie de l'identifiant (oid) du résultat | ||
+ | |- | ||
+ | |orderby (desc) (*) | ||
+ | |L'attribut fera partie de l'ordre de tri | ||
+ | |- | ||
+ | |Caption | ||
+ | |Définit la propriété Caption de la vue | ||
|} | |} | ||
+ | |||
+ | (*) Plusieurs attributs peuvent avoir cette directive, dans ce cas l'ordre de déclaration importe | ||
+ | |||
+ | ===Directive primary=== | ||
+ | |||
+ | {{version11}} | ||
+ | |||
+ | Une vue peut contenir plusieurs directives '''primary''' de type oid | ||
+ | |||
+ | Dans ce cas l'identifiant d'un objet de la vue sera une liste identifiants. | ||
+ | |||
+ | ===Directive orderby=== | ||
+ | |||
+ | {{version11}} | ||
+ | |||
+ | Une vue peut contenir plusieurs directives '''orderby''' | ||
+ | |||
+ | Dans ce cas l'ordre de tri sera défini par la liste des attributs, dans l'ordre de leur déclaration dans la vue. | ||
===Opérateurs=== | ===Opérateurs=== | ||
Ligne 705 : | Ligne 842 : | ||
|sum(A-B) | |sum(A-B) | ||
|- | |- | ||
− | |sumdiff2 (view ope)| | + | |sumdiff2 (view ope)|sumdiff2 |
|3 | |3 | ||
|Retourne la somme de la différence entre trois attributs | |Retourne la somme de la différence entre trois attributs | ||
Ligne 885 : | Ligne 1 022 : | ||
|Réalise une jointure sur une référence | |Réalise une jointure sur une référence | ||
|} | |} | ||
+ | |||
+ | ====Opérateur DateAdd==== | ||
+ | |||
+ | {{version11}} | ||
+ | |||
+ | DateAdd est un opérateur SQL pouvant être utilisé dans la partie littérale d'une expression. | ||
+ | |||
+ | <pre> | ||
+ | dateAdd(dppart, colomn, number) | ||
+ | </pre> | ||
+ | |||
+ | '''Exemple:''' | ||
+ | <source lang="delphi"> | ||
+ | Type | ||
+ | vueSelection = viewOf(TSelectionCompte) | ||
+ | vc:TCompteGeneral = join('(codeCompte>=self.compteInferieur) and (codeCompte<=self.compteSuperieur)'); | ||
+ | vp:TPeriode = join('(1=1)'); | ||
+ | ve:TExercice = join(oid,vp.oidexercice); | ||
+ | ve1:TExercice = join('(?.dateDebut = DateAdd(dpyear,ve.dateDebut,-1))'); | ||
+ | .... | ||
+ | end; | ||
+ | </source> | ||
+ | |||
+ | ====Opérateur GetValue==== | ||
+ | |||
+ | {{version11}} | ||
+ | |||
+ | GetValue est un opérateur script pouvant être utilisé dans la partir littérale d'une expression. | ||
+ | |||
+ | <pre> | ||
+ | GetValue('expression') | ||
+ | </pre> | ||
+ | |||
+ | '''Exemple :''' | ||
+ | <source lang="delphi"> | ||
+ | VueSoldeEcriture = viewOf(TEcriture,VueSoldeComptePeriode) | ||
+ | credit:Currency = credit:TCValue; | ||
+ | debit:Currency = debit:TCValue; | ||
+ | typeLot:Integer = piece.lot.typeLot; | ||
+ | codeCompte:string = compteGeneral.codeCompte; | ||
+ | captionCompte:string = compteGeneral.Caption; | ||
+ | sensCompte:Integer = compteGeneral.sensPrivilegie; | ||
+ | norme:string = piece.normeComptable.code; | ||
+ | eDate:Tdatetime = eDate notInSelect; | ||
+ | [eDate >= GetValue('begin Result := TFacadeInitGeneral.GetPreviousPeriodEndDate(Date); end;')] | ||
+ | end; | ||
+ | </source> | ||
===Agrégat portant sur un montant=== | ===Agrégat portant sur un montant=== | ||
Ligne 934 : | Ligne 1 118 : | ||
|sum (Value) | |sum (Value) | ||
|} | |} | ||
+ | |||
+ | ===Expression SQL=== | ||
+ | |||
+ | Un attribut peut être défini par une expression SQL | ||
+ | |||
+ | <pre> | ||
+ | name:type = expression('...'); | ||
+ | </pre> | ||
+ | |||
+ | * L'expression doit être une expression SQL valide compatible avec le ou les moteurs de base de données utilisés. | ||
+ | * Les alias de table et les paramètres sont substitués. | ||
+ | * Certaine fonctions sont utilisables à la fois sous SQL Server et Oracle dans une expression : | ||
+ | |||
+ | {|class="wikitable" | ||
+ | |- | ||
+ | !Fonction | ||
+ | !Usage | ||
+ | !Oracle | ||
+ | |- | ||
+ | |IsNull(a,b) | ||
+ | |Test si une valeur est nulle | ||
+ | |NVL(a,b) | ||
+ | |- | ||
+ | |DateAdd(part,value,date) | ||
+ | |Ajoute une valeur à une date | ||
+ | |Utilise une fonction utilisateur DateAdd | ||
+ | |- | ||
+ | |DateNotNull | ||
+ | |Constante retournant la date nulle, utilisez cette valeur avec la fonction IsNull(myDate,DateNotNull) | ||
+ | |to_date('18991230','YYYYMMDD') | ||
+ | |- | ||
+ | |NumberNotNull | ||
+ | |Constante retournant une valeur numérique nulle, utilisez cette valeur avec la fonction IsNull(myValue,NumberNotNull) | ||
+ | |'0' | ||
+ | |} | ||
+ | |||
+ | Exemple : | ||
+ | |||
+ | <source lang="delphi"> | ||
+ | Type | ||
+ | VueRoleTiers = viewOf(TCumulPeriodeAuxiliaire) | ||
+ | vnc:TNormeComptable = join(oid,oidnormeComptable); | ||
+ | van:TApprocheNorme = join(oidTNormeComptable,vnc.oid); | ||
+ | vac:TApprocheComptable = join(oid,van.oidTApprocheComptable); | ||
+ | oidApprocheComptable:TOID = vac.oid; | ||
+ | |||
+ | dateDebutPeriode:TDatetime = Periode.dateDebut notInSelect; | ||
+ | dateFinPeriode:TDatetime = Periode.dateFin notInSelect; | ||
+ | |||
+ | idEtablissement:TOID = oidEtablissement; | ||
+ | codeEtablissement:string = Etablissement.code; | ||
+ | libelleEtablissement:string = Etablissement.Caption; | ||
+ | |||
+ | idTiers:TOID = RoleTiers.oidTiers; | ||
+ | codeTiers:string = RoleTiers.Tiers.code; | ||
+ | libelleTiers:String = RoleTiers.Tiers.Caption; | ||
+ | |||
+ | // Avant période | ||
+ | soldeAP_TC:Currency = expression('SUM(CASE WHEN Periode.dateFin < %ArgDateDebutPeriode THEN debitTenue-creditTenue ELSE 0 END)'); | ||
+ | soldeDebitAP_TC:Currency = expression('CASE WHEN SUM(CASE WHEN Periode.dateFin < %ArgDateDebutPeriode THEN debitTenue-creditTenue ELSE 0 END)>0 THEN SUM(CASE WHEN Periode.dateFin < %ArgDateDebutPeriode THEN debitTenue-creditTenue ELSE 0 END) ELSE 0 END'); | ||
+ | soldeCreditAP_TC:Currency = expression('CASE WHEN SUM(CASE WHEN Periode.dateFin < %ArgDateDebutPeriode THEN creditTenue-debitTenue ELSE 0 END)>0 THEN SUM(CASE WHEN Periode.dateFin < %ArgDateDebutPeriode THEN creditTenue-debitTenue ELSE 0 END) ELSE 0 END'); | ||
+ | // sur péridode | ||
+ | debit_TC:Currency = expression('SUM(CASE WHEN Periode.dateDebut >= %ArgDateDebutPeriode THEN debitTenue ELSE 0 END)'); | ||
+ | credit_TC:Currency = expression('SUM(CASE WHEN Periode.dateDebut >= %ArgDateDebutPeriode THEN creditTenue ELSE 0 END)'); | ||
+ | // total | ||
+ | soldeDebit_TC:Currency = sum(debitTenue); | ||
+ | soldeCredit_TC:Currency = sum(creditTenue); | ||
+ | solde_TC:Currency = sumDiff(debitTenue,creditTenue); | ||
+ | // | ||
+ | [(RoleTiers.idOTP=%ArgOTPRoleTiers) and (typeLot>=%ArgTypeDeLot) and (Periode.dateFin<=%ArgDateFinPeriode) and (oidApprocheComptable=%ArgApprocheComptable)] | ||
+ | end; | ||
+ | </source> | ||
+ | |||
+ | ===Vue de modèle utilisant une vue locale=== | ||
+ | |||
+ | {{version2024r1}} | ||
+ | |||
+ | Les vues locales permettent d'exprimer des requêtes complexes qui ne peuvent pas être définies par une vue de modèle. | ||
+ | |||
+ | D'un autre coté, les vues définies dans le modèle peuvent être utilisées dans les interfaces et réutilisées dans le code métier. | ||
+ | |||
+ | Il est possible de définir une vue de modèle utilisant une vue locale pour exprimer la requêtes et bénéficier ainsi des avantages des deux types de vue. | ||
+ | |||
+ | Pour cela: | ||
+ | |||
+ | * Définissez une vue de modèle sur la classe désirée. | ||
+ | * Ajouter les attributs supportés par la vue sans définir d'alias. | ||
+ | * Ajouter une méthode de classe GetSelector retournant un sélecteur d'une vue locale. | ||
+ | |||
+ | <pre> | ||
+ | function TmyView.GetSelector():TSelector; | ||
+ | </pre> | ||
+ | |||
+ | '''Exemple :''' | ||
+ | |||
+ | <source lang="delphi"> | ||
+ | unit CptRubriques; | ||
+ | interface | ||
+ | |||
+ | Type | ||
+ | TVueRubriqueCompte = Class(TSelectionCompte) as strView | ||
+ | {$O modified="2023-09-26T08:15:16" label="Vue des comptes d'une rubrique" options=cloView viewOf=TSelectionCompte viewOrderBy="codeRubrique,codeCompte" viewPrimaryKey="oidCompteGeneral,oidRubrique"} | ||
+ | public | ||
+ | Class Function GetSelector():TSelector; | ||
+ | property codeCompte: String; | ||
+ | property codeRubrique: String; | ||
+ | property CompteGeneral: Ref of TCompteGeneral; | ||
+ | property libelleCompte: String; | ||
+ | property libelleRubrique: String; | ||
+ | property oidCompteGeneral: TOID; | ||
+ | property oidRubrique: TOID; | ||
+ | property oidSelectionCompte: TOID; | ||
+ | property Rubrique: Ref of TRubrique; | ||
+ | property SelectionCompte: Ref of TSelectionCompte; | ||
+ | property sensCompte: Enum(SensPrivilegie); | ||
+ | property sensMontant: Enum(SensRubriqueCpt); | ||
+ | property typeCollectif: Enum(TypeCollectif); | ||
+ | property typeCompte: Enum(TypeCompte); | ||
+ | property typeSelection: Enum(TypeCompte); | ||
+ | end; | ||
+ | |||
+ | {! DIR TVueRubriqueCompte} | ||
+ | {$PO TVueRubriqueCompte.codeCompte label="Code compte"} | ||
+ | {$PO TVueRubriqueCompte.codeRubrique label="Code rubrique"} | ||
+ | {$PO TVueRubriqueCompte.CompteGeneral label="Compte général"} | ||
+ | {$PO TVueRubriqueCompte.libelleCompte label="Libellé compte"} | ||
+ | {$PO TVueRubriqueCompte.libelleRubrique label="Libellé rubrique"} | ||
+ | {$PO TVueRubriqueCompte.SelectionCompte label="Selecteur de compte"} | ||
+ | {$PO TVueRubriqueCompte.sensCompte label="Sens privilégié du compte"} | ||
+ | {$PO TVueRubriqueCompte.sensMontant label="Sens du montant"} | ||
+ | {$PO TVueRubriqueCompte.typeCollectif label="Type collectif du compte"} | ||
+ | {$PO TVueRubriqueCompte.typeCompte label="Type du compte"} | ||
+ | {$PO TVueRubriqueCompte.typeSelection label="Type dans la selection"} | ||
+ | {!END DIR} | ||
+ | |||
+ | |||
+ | {! DOC TVueRubriqueCompte} | ||
+ | {!END DOC} | ||
+ | |||
+ | |||
+ | Implementation | ||
+ | |||
+ | {! METHODS TVueRubriqueCompte} | ||
+ | Class Function TVueRubriqueCompte.GetSelector():TSelector; | ||
+ | Type | ||
+ | vueSelection = viewOf(TSelectionCompte distinct) | ||
+ | vp:TCompteGeneral = join('(codeCompte>=self.compteInferieur) and (codeCompte<=self.compteSuperieur)'); | ||
+ | oidSelectionCompte:TOID = oid; | ||
+ | oidCompteGeneral:TOID = vp.oid primary; | ||
+ | oidRubrique:TOID = oidRubriqueCompte primary; | ||
+ | _Caption:string = _concat(RubriqueCompte.Caption,vp.Caption) caption; // ! _ in front concat is because of CloudFlare | ||
+ | codeRubrique:string = RubriqueCompte.code orderby; | ||
+ | codeCompte:string = vp.codeCompte orderby; | ||
+ | libelleCompte:string = vp.Caption; | ||
+ | libelleRubrique:string = RubriqueCompte.Caption; | ||
+ | sensMontant:Integer = sensMontant; | ||
+ | typeSelection:Integer = typeCompte; | ||
+ | sensCompte:Integer = vp.sensPrivilegie; | ||
+ | typeCollectif:Integer = vp.typeCollectif; | ||
+ | typeCompte:Integer = vp.typeCompte; | ||
+ | end; | ||
+ | |||
+ | begin | ||
+ | Result := vueSelection.CreateSelector('','',True,[]); | ||
+ | end; | ||
+ | |||
+ | {!END METHODS} | ||
+ | end. | ||
+ | </source> | ||
+ | |||
+ | ====Paramètre de GetSelector==== | ||
+ | |||
+ | Il est possible de passer des paramètres à la fonction GetSelector | ||
+ | |||
+ | <pre> | ||
+ | function TmyView.GetSelector(p:TQueryBuilder):TSelector; | ||
+ | </pre> | ||
+ | |||
+ | Exemple : | ||
+ | |||
+ | <source lang="delphi"> | ||
+ | function GetSelector(p:TQueryBuilder):TSelector; | ||
+ | |||
+ | Type | ||
+ | vueEcheanceTC = ... | ||
+ | end; | ||
+ | |||
+ | vueEcheanceTR = ... | ||
+ | end; | ||
+ | |||
+ | begin | ||
+ | if Assigned(p) and p.hasParameter('ArgDeviseTC') and (p.GetParameter('ArgDeviseTC')<>'') | ||
+ | then Result := vueEcheanceTC.CreateSelector('','',True,[]) | ||
+ | else Result := vueEcheanceTR.CreateSelector('','',True,[]); | ||
+ | Result.useCTE := True; | ||
+ | // | ||
+ | if not (Assigned(p) and p.hasParameter('ArgDateRef')) then | ||
+ | begin | ||
+ | Result.AddParameter('ArgDateRef',Date); | ||
+ | end; | ||
+ | end; | ||
+ | </source> | ||
Voir aussi : | Voir aussi : |
Version actuelle en date du 15 juin 2024 à 08:58
Les vues locales sont des type de données vues déclarées localement à l'intérieur d'une opération.
Par exemple le code suivant déclare une vue MyView et effectue une recherche sur cette vue :
function foo(const S:string):Integer; Type MyView = viewof(ClassA) unCode:string = unCodeA; unEntier:Integer = refB.unEntierB; end; var inst:MyView; begin inst := MyView.Find('unCode=%1','',true,['B1']); if Assigned(inst) then begin ... end; end
Le périmètre du type est limité à la procédure, il n'est donc pas possible de passer les objets de la vue en paramètre à d'autres fonctions (pour cela utilisez une vue globale).
La syntaxe pour définir une vue locale :
BNF style grammar : <nom_vue> ::= ViewOf(<class_dec>) [<attributes>] end <class_dec> ::= <class_names> | <class_name> <class_dec> <class_names> ::= <class_name>| [<class_name> ,] <class_name> ::= identifier <class_dec> ::= distinct <attributes> ::= <attribute_def> | <attribute_def> <where_def> <attribute_def> ::= <simple_attribute_def> | <simple_attribute_def> <attribute_directive> <simple_attribute_def> ::= <attribute_dec> | <attribute_dec> = <attribute_ref> <attribute_dec> ::= <attribute_name> : <type_name> <attribute_ref> ::= <main_class_attribute_name> | <operator>(<main_class_attribute_name>) <operator> ::= <aggregate_operator> | <date_operator> | <join_operator> <aggregate_operator> ::= count|sum|max|min <date_operator> ::= year|month|quarter|week|day|dayofyear|dayofweek|hour|minute|second <join_operator> ::= join <attribute_directive> ::= primary | orderby | orderby desc | over | notInSelect <where_def> ::= [ <expression> ] Type NomDeVue = ViewOf(NomDeClassePrincipale) Attribut : Type; Attribut : Type = AliasDe; Attribut : Type = operator(AliasDe); Attribut : Type = AliasDe primary; Attribut : Type = AliasDe orderby; Attribut : Type = AliasDe orderby desc; [ expression ] end;
Les vues peuvent utiles pour effectuer des traitement sur des classes complexes, par exemples :
Exemples
Curseur sur une classe vue
function foo(const S:string):Integer; Type MyView = viewof(ClassA) newCode:string; unCode:string = unCodeA; unEntier:Integer = refB.unEntierB; end; var inst:MyView; cursor:MyViewCursor begin Result := 0; cursor := MyView.CreateCursorWhere(''unCode=%1'','''',true,[S]); foreach inst in cursor do begin Result := Result + inst.unEntier; end; end;
Vue avec jointure externe
function ViewExternalJoin(const S:string):Boolean; Type MyView = viewof(ClassA) newCode:string; unCodeAA:string = unCodeA; unCodeBB:string = refB+unCodeB; end; var inst:MyView; begin inst := MyView.Find('unCodeAA=%1','',true,[S]); if Assigned(inst) and (inst.unCodeAA=S) then Result := True else Result := False; end;
Vue sur une interface
function foo(const S:string):Integer; Type MyView = viewof(InterfaceA, ClassA1, ClassA2) unCode:string = unCodeA primary; .... end; begin ... end;
Vue sur des combinaisons uniques d'attributs
function foo(const S:string):Integer; Type MyView = viewof(ClassA distinct) unCode:string = unCodeA primary; unEntier:Integer = refB.unEntierB; end; begin ... end;
Vue avec agrégats
function foo(const S:string):Integer; Type MyView = viewof(ClassA) unCode:string = unCodeA primary; unEntier:Integer = sum(unEntier); end; begin ... end;
Vue avec agrégats sur un montant
Type myView = viewof(WFClasseX) mysum:TMoney = sum(credit) orderby; end; var sel:TSelector; inst:MyView; S,stag:string; begin sel := MyView.CreateSelector('','',true,[]); S := ''; stag := ''; foreach inst in Sel.AsCursor do begin S := S+stag+Formatfloat('0.00',inst.mysum.Value); stag := ','; end; showmessage(S); Result := FALSE; end;
select sum(t0.credit) "mysum",t0.credit_CodeDevise "mysum_CodeDevise" from dbo.WFCLASSEX t0 group by t0.credit_CodeDevise order by sum(t0.credit)
Vue avec agrégats sur un attribut enfant
Type myView = viewof(WFClasseX) mysum:TMoney = sum(credit:TCValue) orderby; end; begin ... end;
select sum(t0.credit_TCValue) "mysum" from dbo.WFCLASSEX t0 order by sum(t0.credit_TCValue)
Vue avec un opérateur de date
function foo(const S:string):Integer; Type MyView = viewof(ClassC distinct) unCode:string = unCodeC primary; unMois:Integer = month(uneDate); end; begin ... end;
Vue avec un opérateur de date (diff)
function foo(iDayDiff):string; Type MyView = viewof(ClassC distinct) unCode:string = unCodeC primary; DayDiff:Integer = DayDiff(uneDateStart,uneDateEnd); end; begin inst := MyView.Find('DayDiff >= %1','',true,[iDayDiff]); if Assigned(inst) then Result := inst.unCode else Result := 'Not found'; end;
Vue avec référence
function foo(const S:string):Integer; Type MyView = viewof(ClassA) unCodeAA:string = unCodeA; refB:reference = refB; end; begin ... end;
function foo(const S:string):Integer; Type MyView = viewof(ClassA) unCodeAA:string = unCodeA; refB:ClassB = refB; end; begin ... end;
Vue avec variable référence
function foo(const S:string):Integer; Type MyView = viewof(ClassA) unCodeAA:string = unCodeA; refB:ClassB; end; begin ... end;
Vue avec filtre
function foo(const S:string):Integer; Type MyView = viewof(ClassA) unCodeAA:string = unCodeA; unCodeBB:string = refB.unCodeB; [ unCodeA='A1' ] end; begin ... end;
Vue avec traversée de liste
function _Concat(const S:string):string; Type MyView = viewof(ClassF) unCodeF:string = unCodeF; unCodeG:string = refFG.unCodeG; unCodeH:string = refFG.listH.unCodeH; end; var ls:MyViewList; stag:string; idx:integer; begin ls := MyView.CreateListWhere('unCodeG=%1','','unCodeH',true,-1,[S]); Result := ''; stag := ''; for idx:=0 to ls.Count-1 do begin Result := Result+stag+ls.Refs[idx].unCodeH; stag := ','; end; end;
Vue avec jointure sur une classe
Type myView = class(myClass) vp1:joinClass1 = join(A,B); vp2:JoinClass2 = join(A,B,W); vp3:JoinClass3 = join(W); .... end;
Paramètre | Usage |
---|---|
A | Attribut de la classe join (joinClass) |
B | Chemin à partir de la classe base (myView) |
W | Clause Where sur la classe join |
La clause Where peut être exprimée avec les préfixes :
self | Préfixe de la classe de base |
? | Préfixe de la classe Join |
xx | alias d'une jointure de classe |
Tip : Il est possible de créer un produit cartésien entre deux classes en utilisant une jointure avec une clause where toujours vraie. |
//Procedure expensePendings(req:Tjson; var res:TObject); Type ExpenseView = viewOf(TNoteFrais) vp: TValideurPossible = join(ValidationEtat.EtatPossible.EtatMetier, EtatNF); aManager:string = vp.ContactEtablissement.oidutilisateur; // aDate:TDatetime = nDate; aRef:string = referencePiece; aReason:string = Caption; aAmountOrg:TMoney = MontantTTC; aAmountAct:TMoney = MontantRetenu; aQuantity:TQuantity = Quantite; aUser:string = Salarie.Operateur.oidutilisateur; aType:string = FraisSalarie.Caption; aMode:Integer = FraisSalarie.modeRemboursement; aAmountMax:TMoney = FraisSalarie.montantPlafond; aStatus:Integer = Statut; end; var json:TJson; ls:TSelector; indx,ctn:Integer; inst:ExpenseView; AWhere,AOrder:string; Args:Array[0..5] of variant; begin json := TJson.Create(''); res := json; // AWhere := '(aManager=%1) and (aStatus=%2)'; Args[0] := GlbUserName; Args[1] := StatutNF_AValider; AOrder := 'aUser,-aDate'; indx := 0; ctn := 0; ls := ExpenseView.CreateSelector(AWhere,AOrder,true,Args); foreachP inst in ls.AsCursor do begin . . . end; end;
Dans cet exemple le modèle est celui-ci :
La classe TEtatMetier est atteinte par deux chemins différents, un issu de la classe TValideurPossible et un issu de la classe TNoteFrais. La jointure est réalisée sur l'objet TEtatMetier.
vp: TValideurPossible = join(ValidationEtat.EtatPossible.EtatMetier, EtatNF);
- TValideurPossible est la classe qui va être jointe
- vp défini un alias sur cette classe qui peut être ensuite utilisé dans la définition de la vue.
- ValidationEtat.EtatPossible.EtatMetier est le chemin issu de la classe jointe
- EtatNF est le chemin issu de la classe de la vue.
Exemple, vue locale avec produit cartésien, jointure par clause where et sous requêtes
//procedure RubriqueParExerciceDetail; Type vueSolde = viewof(TCumulPeriodeCompte) codeCompte:string = CompteGeneral.codeCompte; datePeriode:TDatetime = Periode.dateDebut; value:Currency = sumDiff(debitTenue,creditTenue); oidExercice:TOID = Periode.oidexercice; [(typeLot=1)] end; vueSelection = viewOf(TSelectionCompte) vc:TCompteGeneral = join('(codeCompte>=self.compteInferieur) and (codeCompte<=self.compteSuperieur)'); vp:TPeriode = join('(1=1)'); ve:TExercice = join(oid,vp.oidexercice); ve1:TExercice = join('(?.dateDebut = DateAdd(dpyear,ve.dateDebut,-1))'); // idCompteGeneral:TOID = vc.oid primary; idRubrique:TOID = oidRubriqueCompte primary; idPeriode:TOID = vp.oid primary; idExercice:TOID = vp.oidexercice; idExerciceN1:TOID = ve1.oid; // codeRubrique:string = RubriqueCompte.code orderby; libelleRubrique:string = RubriqueCompte.Caption; codeCompte:string = vc.codeCompte orderby; libelleCompte:string = vc.Caption; libellePeriode:string = vp.Caption; // datePeriode:TDatetime = vp.dateDebut orderby desc; year:Integer = year(vp.dateDebut); month:Integer = month(vp.dateDebut); valueN0:currency = VueSolde.select('value','(oidExercice=self.idExercice) and (codeCompte=self.codeCompte) and (datePeriode<=self.datePeriode)','',true,[]); valueN1:currency = VueSolde.select('value','(oidExercice=self.idExerciceN1) and (codeCompte=self.codeCompte) and (datePeriode<=DateAdd(dpYear,self.datePeriode,-1))','',true,[]); end; var Sel:TSelector; inst:vueSelection; S,stag:string; begin Sel := vueSelection.CreateSelector('(codeRubrique=%1) and (year=2022) and (month=3)','',True,['SIG.L02']); S := ''; stag := ''; forEach inst in Sel.AsCursor do begin S := S+stag+inst.codeCompte; stag := ','; end; showMessage(S); end;
Tip : Notez l'opérateur SQL DateAdd() qui peut être utilisé dans la partie littérale d'une expression |
Vue avec jointures liées
Type VueValideur = viewOf(TPieceTaxable) vp1: TValideurPossible = join(ValidationEtat.EtatPossible.EtatMetier,EtatMetier); vp2: TValideurPossible = join(ValidationEtat.RegleValidation,RegleValidation); gcv: TGroupeContactValidation = leftjoin(TGroupeValidation,vp2.ContactEtablissement); aId1:TOID = vp1.oid; aId2:TOID = vp2.oid; // ... [ (aId1=aId2) and ... ] end;
Dans cet exemple :
- vp1 et vp2 sont deux jointures qui coincident sur le même tuple.
- La coincidence des deux jointures est réalisée par le clause where (aId1=aId2)
- gcv est une jointure sur le tuple défini par vp1 et vp2
Jointure avec filtre idOTP
Utilisez la fonction littérale OTP() pour filtrer sur la valeur de idOTP
Exemple :
Type vueSoldeClient = viewOf(TCumulPeriodeAuxiliaire) vnc:TNormeComptable = join(oid,oidnormeComptable); van:TApprocheNorme = join(oidTNormeComptable,vnc.oid); vac:TApprocheComptable = join(oid,van.oidTApprocheComptable); vrt:TRoleTiers = join(oid,oidroleTiers,'(?.idOTP = OTP(''TClient''))'); codeApproche:string = vac.code; idTiers:TOID = vrt.oidTiers; solde:Currency = sumDiff(debitTenue,creditTenue); [(typeLot=1) and (codeApproche='NAT')] end;
Vue avec sous requêtes
Il est possible de générer une sous requête liée à la requête principale en utilisant la méthode SELECT d'un sélecteur.
La sous requêtes doit être liée à la requête principale en utilisant l'opérateur self dans la clause Where du SELECT.
Une sous requêtes peut être utilisée soit dans la liste des colonnes, soit dans la clause Where du selecteur.
Utilisation dans les colonnes :
Type Vue1 = viewOf(MyClass) sub1:TMoney = sum(...); id1:TOID = ....; .... end; Vue2 = viewOf(MyClass) sum1:TMoney = sum(...); sum2:TMoney = Vue1.Select('sub1','(id1=self.id2)','',true,[]); id2:TOID = ...; .... end; var sel:TSelector; begin sel := Vue2.CreateSelector('','',true,[]); // ... end;
Utilisation dans la clause Where :
Type Vue1 = viewOf(MyClass) sub1:TMoney = sum(...); id1:TOID = ....; .... end; Vue2 = viewOf(MyClass) sum1:TMoney = sum(...); id2:TOID = ...; .... end; var sel:TSelector; begin sel := Vue2.CreateSelector('(sum1>%1)','',true,[ Vue1.Select('sub1','(id1=self.id2)','',true,[]) ]); // ... end;
Avec des paramètres :
Il est possible de paramétrer une sous requête en utilisant les paramètres de la requête principale :
Type Vue1 = viewOf(MyClass) sub1:TMoney = sum(...); id1:TOID = ....; col1:string = ...; col2:Integer = ...; .... end; Vue2 = viewOf(MyClass) sum1:TMoney = sum(...); sum2:TMoney = Vue1.Select('sub1','(id1=self.id2) and (col=%1) and (col2=%2)','',true,[]); id2:TOID = ...; .... end; var sel:TSelector; begin sel := Vue2.CreateSelector('','',true,['valueCol1',1,....]); // ... end;
Vue avec interface (Union)
Il est possible d'utiliser une interface pour générer une union de plusieurs vues locales supportant cette interface
Exemple :
Type ISoldeCompte = interface credit:Currency; debit:Currency; typeLot:Integer; codeCompte:string; captionCompte:string; sensCompte:Integer; norme:string; end; VueSoldeComptePeriode = viewOf(TCumulPeriodeCompte,ISoldeCompte) credit:Currency = creditTenue; debit:Currency = debitTenue; typeLot:Integer = typeLot; codeCompte:string = compteGeneral.codeCompte; captionCompte:string = compteGeneral.Caption; sensCompte:Integer = compteGeneral.sensPrivilegie; norme:string = normeComptable.code; dateFin:Tdatetime = Periode.dateFin notInSelect; [dateFin < GetDate] end; VueSoldeEcriture = viewOf(TEcriture,VueSoldeComptePeriode) credit:Currency = credit:TCValue; debit:Currency = debit:TCValue; typeLot:Integer = piece.lot.typeLot; codeCompte:string = compteGeneral.codeCompte; captionCompte:string = compteGeneral.Caption; sensCompte:Integer = compteGeneral.sensPrivilegie; norme:string = piece.normeComptable.code; eDate:Tdatetime = eDate notInSelect; [eDate >= GetValue('begin Result := TFacadeInitGeneral.GetPreviousPeriodEndDate(Date); end;')] end; VueSoldeCompte = viewOf(ISoldeCompte,VueSoldeComptePeriode,VueSoldeEcriture) solde:Currency = sumSens(credit,debit,sensCompte); typeLot:Integer = typeLot; codeCompte:string= codeCompte; captionCompte:string = captionCompte; sensCompte:Integer = sensCompte; norme:string= norme notInSelect; end; var ls:TSelector; inst:VueSoldeCompte; doc:TxmlhtmlMailDocument; Table:ThtmlTable; ANorme1,ANorme2:string; begin ls := VueSoldeCompte.CreateSelector('(codeCompte like %1) and (typeLot=%2) and ((norme=%3)or(norme=%4))','',true,[ _StrLike(prefixeCompte), typeLot.Value, ANorme1, ANorme2 ]); ... end;
Vue utilisant une CTE (Commun table expression)
Il est possible de générer une requête CTE :
- En utilisant une directive "over" dans la définition d'une colonne
- En positionant la propriété useCTE sur le sélecteur.
Le code SQL généré sera
With CTE AS ( ) SELECT * from CTE
Lorsqu'une CTE est utilisée la clause Where du sélecteur s'applique sur résultat de la CTE.
Type Vue1 = viewOf(MyClass) sub1:TMoney = sum(...); id1:TOID = ....; .... end; Vue2 = viewOf(MyClass) sum1:TMoney = sum(...); sum2:TMoney = Vue1.Select('sub1','(id1=self.id2)','',true,[]); id2:TOID = ...: end; var sel:TSelector; begin sel := Vue2.CreateSelector('(sum1 > sum2)','',true,[]); sel.UseCTE := True; // ... end;
Directive d'attribut
Directive | Action |
---|---|
notInSelect | L'attribut ne sera pas généré dans clause select |
over | L'attribut est généré par rapport à la requête CTE |
primary (*) | L'attribut fera partie de l'identifiant (oid) du résultat |
orderby (desc) (*) | L'attribut fera partie de l'ordre de tri |
Caption | Définit la propriété Caption de la vue |
(*) Plusieurs attributs peuvent avoir cette directive, dans ce cas l'ordre de déclaration importe
Directive primary
Une vue peut contenir plusieurs directives primary de type oid
Dans ce cas l'identifiant d'un objet de la vue sera une liste identifiants.
Directive orderby
Une vue peut contenir plusieurs directives orderby
Dans ce cas l'ordre de tri sera défini par la liste des attributs, dans l'ordre de leur déclaration dans la vue.
Opérateurs
Opérateur portant sur une colonne
Opérateur | Arguments | Action | Opération |
---|---|---|---|
isNull | 2 | Retourne la valeur de la colonne 2 si la valeur de la colonne 1 est nulle | case A is NULL then B else A |
Exemple d'utilisation de isNull
Type VueValideur = viewOf(TPieceTaxable) vp1: TValideurPossible = join(ValidationEtat.EtatPossible.EtatMetier,EtatMetier); vp2: TValideurPossible = join(ValidationEtat.RegleValidation,RegleValidation); gcv: TGroupeContactValidation = leftjoin(TGroupeValidation,vp2.ContactEtablissement); aId1:TOID = vp1.oid; aId2:TOID = vp2.oid; aIdVP:TOID = vp2.oidValideurPrecedent; aIdDV:TOID = oiddernierValideur; aIdCV:TOID = vp2.oidContactEtablissement; // contact établissement valideur, peut être membre du groupe de validation ou le valideur défini par la règle aIdCE:TOID = ISNULL(gcv.oidTContactEtablissement,vp2.oidContactEtablissement); // personne Mail:string = ISNULL(gcv.TContactEtablissement+eMail,vp2.ContactEtablissement.eMail); // [ (aId1=aId2) ... ] end;
Opérateur portant sur un type numérique
Opérateur | Arguments | Action | Opération |
---|---|---|---|
sum | 1 | Effectue la somme de l'attribut | sum(A) |
min | 1 | Retourne le minimum de l'attribut | min(A) |
max | 1 | Retourne le max de l'attribut | max(A) |
add | 2 | Retourne la somme de deux attributs | A+B |
sub | 2 | Retourne la différence entre deux attributs | A-B |
mul | 2 | Retourne la multiplication de deux attributs | A*B |
div | 2 | Retourne la divition de deux attributs | A/B |
percent | 2 | Retourne le poucentage entre deux attributs | case when B=0 then 0 else (100*A / B) end |
sumdiff | 2 | Retourne la somme de la différence entre deux attributs | sum(A-B) |
sumdiff2 | 3 | Retourne la somme de la différence entre trois attributs | sum(A+B-C) |
mindiff | 2 | Retourne le min de la différence entre deux attributs | min(A-B) |
maxdiff | 2 | Retourne le max de la différence entre deux attributs | max(A-B) |
sumconcat | 2 | Retourne la somme de la somme entre deux attributs | sum(A+B) |
minconcat | 2 | Retourne la min de la somme entre deux attributs | min(A+B) |
maxconcat | 2 | Retourne le max de la somme entre deux attributs | max(A+B) |
count | 1 | Compte le nombre de lignes | count(*) |
Opérateur | Arguments | Action | Opération |
---|---|---|---|
sumDiffP | 2 | Retourne la somme de la différence si elle positive et 0 sinon. | case sum(A-B)>0 then sum(A-B) else 0 |
sumDiffA | 2 | Retourne la valeur absolue de la différence. | ABS(sum(A-B)) |
sumDiffS | 2 | Retourne le signe de la différence | case sum(A-B)>0 then 1 else 0 |
Opérateur | Arguments | Action | Operation |
---|---|---|---|
sum | 1,2,3 | Effectue la somme des attributs | sum(A), sum(A+B),sum(A+B+C) |
sumCase | 3 | Somme de l'attribut suivant une condition | sum(case B=C then A else 0) |
sumSign | 3 | Somme signée de l'attribut suivant une condition | sum(case B=C then A else -A) |
sumSens | 3 | Somme suivant le sens comptable (A=Credit, B=Débit, C=Sens, Sens=1=Débit) | sum(case C=1 then B-A else A-B) |
Opérateur portant sur une chaine
Opérateur | Arguments | Action | Opération |
---|---|---|---|
concat | 2 | Concaténation de deux attributs chaîne | concat (A,B) |
Opérateur portant sur OID
Opérateur | Arguments | Action |
---|---|---|
count | 1 | Compte les éléments de la vue |
Opérateur portant sur une date
Ces opérateur prennent une date comme argument.
Opérateur | Arguments | Action |
---|---|---|
year | 1 | Retourne l'année de la date |
quarter | 1 | Retourne le trimestre de la date |
month | 1 | Retourne le mois de la date |
dayofyear | 1 | Retourne le jour de l'année de la date |
dayofweek | 1 | Retourne le jour de la semaine de la date |
hour | 1 | Retourne le nombre d'heures de la date |
minute | 1 | Retourne le nombre de minutes de la date |
second | 1 | Retourne le nombre de secondes de la date |
millisecond | 1 | Retourne le nombre de millisecondes de la date |
daydiff | 2 | Retourne le nombre de jour entre deux dates |
Opérateur portant sur une référence
Opérateur | Arguments | Action |
---|---|---|
join | 2 | Réalise une jointure sur une référence |
Opérateur DateAdd
DateAdd est un opérateur SQL pouvant être utilisé dans la partie littérale d'une expression.
dateAdd(dppart, colomn, number)
Exemple:
Type vueSelection = viewOf(TSelectionCompte) vc:TCompteGeneral = join('(codeCompte>=self.compteInferieur) and (codeCompte<=self.compteSuperieur)'); vp:TPeriode = join('(1=1)'); ve:TExercice = join(oid,vp.oidexercice); ve1:TExercice = join('(?.dateDebut = DateAdd(dpyear,ve.dateDebut,-1))'); .... end;
Opérateur GetValue
GetValue est un opérateur script pouvant être utilisé dans la partir littérale d'une expression.
GetValue('expression')
Exemple :
VueSoldeEcriture = viewOf(TEcriture,VueSoldeComptePeriode) credit:Currency = credit:TCValue; debit:Currency = debit:TCValue; typeLot:Integer = piece.lot.typeLot; codeCompte:string = compteGeneral.codeCompte; captionCompte:string = compteGeneral.Caption; sensCompte:Integer = compteGeneral.sensPrivilegie; norme:string = piece.normeComptable.code; eDate:Tdatetime = eDate notInSelect; [eDate >= GetValue('begin Result := TFacadeInitGeneral.GetPreviousPeriodEndDate(Date); end;')] end;
Agrégat portant sur un montant
C'est le type de l'attribut défini dans la vue qui détermine le résultat de l'agrégation.
Les opération d'agrégation effectuent un groupement par devise et agrègent les valeurs de montant (en devise, tenue de compte et reporting). Les chaînes de conversion sont à vides et la date de cours est la date du jour.
Type Source | Type Vue | Opération |
---|---|---|
source:Money | vue:Money = sum(source) | sum(Value) group by CodeDevise |
source:MoneyDT | vue:Money = sum(source) | sum(Value) group by CodeDevise |
source:Money | vue:MoneyDT = sum(source) | ** ERREUR ** |
source:MoneyDT | vue:MoneyDT = sum(source) | sum(Value) group by CodeDevise |
source:Money | vue:Currency = sum(source) | sum (Value) |
source:MoneyDT | vue:Currency = sum(source) | sum (Value) |
source:MoneyDT | vue:Currency = sum(source:TCValue) | sum (TCValue) |
source:MoneyDT | vue:Currency = sum(source:RPValue) | sum (RPValue) |
source:Currency | vue:Currency = sum(source) | sum (Value) |
Expression SQL
Un attribut peut être défini par une expression SQL
name:type = expression('...');
- L'expression doit être une expression SQL valide compatible avec le ou les moteurs de base de données utilisés.
- Les alias de table et les paramètres sont substitués.
- Certaine fonctions sont utilisables à la fois sous SQL Server et Oracle dans une expression :
Fonction | Usage | Oracle |
---|---|---|
IsNull(a,b) | Test si une valeur est nulle | NVL(a,b) |
DateAdd(part,value,date) | Ajoute une valeur à une date | Utilise une fonction utilisateur DateAdd |
DateNotNull | Constante retournant la date nulle, utilisez cette valeur avec la fonction IsNull(myDate,DateNotNull) | to_date('18991230','YYYYMMDD') |
NumberNotNull | Constante retournant une valeur numérique nulle, utilisez cette valeur avec la fonction IsNull(myValue,NumberNotNull) | '0' |
Exemple :
Type VueRoleTiers = viewOf(TCumulPeriodeAuxiliaire) vnc:TNormeComptable = join(oid,oidnormeComptable); van:TApprocheNorme = join(oidTNormeComptable,vnc.oid); vac:TApprocheComptable = join(oid,van.oidTApprocheComptable); oidApprocheComptable:TOID = vac.oid; dateDebutPeriode:TDatetime = Periode.dateDebut notInSelect; dateFinPeriode:TDatetime = Periode.dateFin notInSelect; idEtablissement:TOID = oidEtablissement; codeEtablissement:string = Etablissement.code; libelleEtablissement:string = Etablissement.Caption; idTiers:TOID = RoleTiers.oidTiers; codeTiers:string = RoleTiers.Tiers.code; libelleTiers:String = RoleTiers.Tiers.Caption; // Avant période soldeAP_TC:Currency = expression('SUM(CASE WHEN Periode.dateFin < %ArgDateDebutPeriode THEN debitTenue-creditTenue ELSE 0 END)'); soldeDebitAP_TC:Currency = expression('CASE WHEN SUM(CASE WHEN Periode.dateFin < %ArgDateDebutPeriode THEN debitTenue-creditTenue ELSE 0 END)>0 THEN SUM(CASE WHEN Periode.dateFin < %ArgDateDebutPeriode THEN debitTenue-creditTenue ELSE 0 END) ELSE 0 END'); soldeCreditAP_TC:Currency = expression('CASE WHEN SUM(CASE WHEN Periode.dateFin < %ArgDateDebutPeriode THEN creditTenue-debitTenue ELSE 0 END)>0 THEN SUM(CASE WHEN Periode.dateFin < %ArgDateDebutPeriode THEN creditTenue-debitTenue ELSE 0 END) ELSE 0 END'); // sur péridode debit_TC:Currency = expression('SUM(CASE WHEN Periode.dateDebut >= %ArgDateDebutPeriode THEN debitTenue ELSE 0 END)'); credit_TC:Currency = expression('SUM(CASE WHEN Periode.dateDebut >= %ArgDateDebutPeriode THEN creditTenue ELSE 0 END)'); // total soldeDebit_TC:Currency = sum(debitTenue); soldeCredit_TC:Currency = sum(creditTenue); solde_TC:Currency = sumDiff(debitTenue,creditTenue); // [(RoleTiers.idOTP=%ArgOTPRoleTiers) and (typeLot>=%ArgTypeDeLot) and (Periode.dateFin<=%ArgDateFinPeriode) and (oidApprocheComptable=%ArgApprocheComptable)] end;
Vue de modèle utilisant une vue locale
Les vues locales permettent d'exprimer des requêtes complexes qui ne peuvent pas être définies par une vue de modèle.
D'un autre coté, les vues définies dans le modèle peuvent être utilisées dans les interfaces et réutilisées dans le code métier.
Il est possible de définir une vue de modèle utilisant une vue locale pour exprimer la requêtes et bénéficier ainsi des avantages des deux types de vue.
Pour cela:
- Définissez une vue de modèle sur la classe désirée.
- Ajouter les attributs supportés par la vue sans définir d'alias.
- Ajouter une méthode de classe GetSelector retournant un sélecteur d'une vue locale.
function TmyView.GetSelector():TSelector;
Exemple :
unit CptRubriques; interface Type TVueRubriqueCompte = Class(TSelectionCompte) as strView {$O modified="2023-09-26T08:15:16" label="Vue des comptes d'une rubrique" options=cloView viewOf=TSelectionCompte viewOrderBy="codeRubrique,codeCompte" viewPrimaryKey="oidCompteGeneral,oidRubrique"} public Class Function GetSelector():TSelector; property codeCompte: String; property codeRubrique: String; property CompteGeneral: Ref of TCompteGeneral; property libelleCompte: String; property libelleRubrique: String; property oidCompteGeneral: TOID; property oidRubrique: TOID; property oidSelectionCompte: TOID; property Rubrique: Ref of TRubrique; property SelectionCompte: Ref of TSelectionCompte; property sensCompte: Enum(SensPrivilegie); property sensMontant: Enum(SensRubriqueCpt); property typeCollectif: Enum(TypeCollectif); property typeCompte: Enum(TypeCompte); property typeSelection: Enum(TypeCompte); end; {! DIR TVueRubriqueCompte} {$PO TVueRubriqueCompte.codeCompte label="Code compte"} {$PO TVueRubriqueCompte.codeRubrique label="Code rubrique"} {$PO TVueRubriqueCompte.CompteGeneral label="Compte général"} {$PO TVueRubriqueCompte.libelleCompte label="Libellé compte"} {$PO TVueRubriqueCompte.libelleRubrique label="Libellé rubrique"} {$PO TVueRubriqueCompte.SelectionCompte label="Selecteur de compte"} {$PO TVueRubriqueCompte.sensCompte label="Sens privilégié du compte"} {$PO TVueRubriqueCompte.sensMontant label="Sens du montant"} {$PO TVueRubriqueCompte.typeCollectif label="Type collectif du compte"} {$PO TVueRubriqueCompte.typeCompte label="Type du compte"} {$PO TVueRubriqueCompte.typeSelection label="Type dans la selection"} {!END DIR} {! DOC TVueRubriqueCompte} {!END DOC} Implementation {! METHODS TVueRubriqueCompte} Class Function TVueRubriqueCompte.GetSelector():TSelector; Type vueSelection = viewOf(TSelectionCompte distinct) vp:TCompteGeneral = join('(codeCompte>=self.compteInferieur) and (codeCompte<=self.compteSuperieur)'); oidSelectionCompte:TOID = oid; oidCompteGeneral:TOID = vp.oid primary; oidRubrique:TOID = oidRubriqueCompte primary; _Caption:string = _concat(RubriqueCompte.Caption,vp.Caption) caption; // ! _ in front concat is because of CloudFlare codeRubrique:string = RubriqueCompte.code orderby; codeCompte:string = vp.codeCompte orderby; libelleCompte:string = vp.Caption; libelleRubrique:string = RubriqueCompte.Caption; sensMontant:Integer = sensMontant; typeSelection:Integer = typeCompte; sensCompte:Integer = vp.sensPrivilegie; typeCollectif:Integer = vp.typeCollectif; typeCompte:Integer = vp.typeCompte; end; begin Result := vueSelection.CreateSelector('','',True,[]); end; {!END METHODS} end.
Paramètre de GetSelector
Il est possible de passer des paramètres à la fonction GetSelector
function TmyView.GetSelector(p:TQueryBuilder):TSelector;
Exemple :
function GetSelector(p:TQueryBuilder):TSelector; Type vueEcheanceTC = ... end; vueEcheanceTR = ... end; begin if Assigned(p) and p.hasParameter('ArgDeviseTC') and (p.GetParameter('ArgDeviseTC')<>'') then Result := vueEcheanceTC.CreateSelector('','',True,[]) else Result := vueEcheanceTR.CreateSelector('','',True,[]); Result.useCTE := True; // if not (Assigned(p) and p.hasParameter('ArgDateRef')) then begin Result.AddParameter('ArgDateRef',Date); end; end;
Voir aussi :