Vous êtes sur le site Web historique de la documentation de 4D. Les documentations sont progressivement déplacées vers developer.4d.com

Accueil

 
4D v19
Sélections d'entités

Sélections d'entités  


 

Aperçu  

Une sélection d'entités est un objet contenant une ou plusieurs référence(s) à des entités appartenant à la même dataclass. Une sélection d'entités peut contenir 0, 1 ou X entités de la dataclass - où X peut représenter le nombre total d'entités contenues dans la dataclass

Les sélections d'entités peuvent être :

  • "partageables" ou "altérables"
  • "ordonnées" ou "non ordonnées"

Ces points sont examinés ci-dessous.

Les sélections d'entités sont généralement créées à l'aide d'une requête ou renvoyés à partir d'un attribut relationnel. Par exemple :

 brokers:=ds.Person.query("personType = broker")

Ce code renvoie dans brokers toutes les personnes de type courtier. Pour accéder à une entité de la sélection, utilisez une syntaxe similaire à l'accès à un élément dans une collection. Par exemple :

 theBroker:=brokers[0]  //Les sélections d'entités sont basées sur 0

La méthode entitySelection.orderBy( ) retourne une nouvelle sélection d'entités en fonction de critères de tri fournis. Par exemple :

 brokers:=brokers.orderBy("name") //renvoie une sélection triée

Ce code renvoie dans brokers la même sélection d'entités de Person, mais triée par nom.

Vous pouvez également utiliser un attribut relationnel pour renvoyer une sélection d'entités. Par exemple :

 brokers:=ds.Person.query("personType = broker")
 brokerCompanies:=brokers.myCompany

Ce code assigne à brokerCompanies toutes les sociétés liées à des personnes de la sélection d'entités brokers, en utilisant l'attribut relationnel myCompany. L'utilisation des attributs relationnels sur les sélections d'entités est un moyen puissant et facile de naviguer dans la chaîne des entités associées.

Pour effectuer des actions répétées sur des entités dans une sélection d'entités, comme récupérer et modifier des valeurs de certains attributs, vous pouvez utiliser la structure Pour chaque...Fin de chaque. Par exemple :

 C_OBJET(emp)
 Pour chaque(emp;ds.Employees.all())
    Si(emp.Country="UK")
       emp.salary:=emp.salary*1,03
       emp.save()
    Fin de si
 Fin de chaque

 
 

Vous pouvez créer un objet de type sélection d'entités comme suit :

  • En interrogeant les entités dans une dataclass (voir la méthode dataClass.query( )) ;
  • En utilisant la méthode dataClass.all( ) pour sélectionner toutes les entités d'une dataclass ;
  • En utilisant la commande Creer entity selection pour créer une sélection d'entité basée sur la sélection courante d'une table 4D ;
  • En utilisant la fonction dataClass.newSelection( ) pour créer un objet sélection d'entité vide ;
  • En utilisant une des diverses méthodes du thème ORDA - EntitySelection qui renvoie une nouvelle sélection d'entités, telle que entitySelection.or( ) ;
  • En utilisant un attribut de type "related entities" (voir ci-dessous).

Vous pouvez simultanément créer et utiliser autant de sélection d'entités que vous le souhaitez pour une dataclass. Gardez à l'esprit qu'une sélection d'entités contient uniquement des références à des entités. Des sélections d'entités différentes peuvent contenir des références aux mêmes entités.

Note : Une sélection d'entités peut être utilisée dans différents process si elle est partageable. Pour plus d'informations, reportez-vous au paragraphe Sélections d'entité partageables et non partageables ci-dessous.

Tous les attributs de stockage (texte, nombre, booléen, date) sont disponibles en tant que propriétés des sélections d'entités et des entités. Lorsqu'il est utilisé conjointement avec une sélection d'entité, un attribut scalaire renvoie une collection de valeurs scalaires. Par exemple :

 locals:=ds.Person.query("city = :1";"San Jose") //Sélection des entités Person
 localEmails:=locals.emailAddress //collection des adresses e-mail (chaînes)

Ce code renvoie dans localEmails une collection d'adresses e-mail sous forme de chaînes.

En plus de la variété de méthodes que vous pouvez utiliser, vous pouvez également utiliser les attributs relationnels comme propriétés des sélections d'entités pour renvoyer de nouvelles sélection d'entités. Par exemple, considérez la structure suivante :

 myParts:=ds.Part.query("ID < 100") //Retourne Parts avec un ID inférieur à 100
 $myInvoices:=myParts.invoiceItems.invoice
  //Toutes les factures ("Invoice") avec au moins une ligne ("InvoiceItem") reliée à un produit ("Part") dans myParts

La dernière ligne retournera dans $myInvoices une sélection d'entités de toutes les factures qui ont au moins un élément de factures lié à une partie de sélection d'entités dans myParts. Lorsqu'un attribut relationnel est utilisé en tant que propriété d'une sélection d'entités, le résultat est toujours une autre sélection d'entités, même si une seule entité est renvoyée. Lorsqu'un attribut relationnel est utilisé en tant que propriété d'une sélection d'entités et qu'aucune entité n'est renvoyée, le résultat est une sélection d'entités vide, et non null

Une sélection d'entité peut être partageable (lisible par plusieurs process, mais non modifiable après création) ou altérable (prend en charge la fonction entitySelection.add( ), mais utilisable uniquement par le process courant) :

  • une sélection d'entités partageable présente les caractéristiques suivantes :
    • elle peut être stockée dans un objet ou une collection partagé(e), et peut être passée comme paramètre entre plusieurs process ou workers;
    • elle peut être stockée dans plusieurs objets ou collections partagé(e)s, ou dans un objet ou une collection partagé(e) qui appartient déjà à un groupe (sans identifiant de verrouillage).
    • elle ne permet pas d'ajouter de nouvelles entités. Essayer d'ajouter une entité à une sélection d'entité partageable génèrera une erreur (1637 - Cette sélection d'entité ne peut pas être modifiée). Pour ajouter une entité à une sélection d'entité partageable, vous devez d'abord la transformer en une sélection d'entité non partageable à l'aide de la fonction entitySelection.copy( ), avant d'appeler entitySelection.add( ).

Note : La plupart des fonctions de sélections d'entités (telles que entitySelection.slice( ), entitySelection.and( ), etc.) prennent en charge les sélections d'entités partageables car elles n'ont pas besoin de modifier la sélection d'entités d'origine (elles en retournent une nouvelle).

  • une sélection d'entité altérable présente les caractéristiques suivantes :
    • elle ne peut pas être partagée entre les process, ni être stockée dans un objet ou une collection partagé(e). Essayer de stocker une sélection d'entité non partageable dans un objet ou une collection partagé(e) génèrera une erreur (-10721 - Type de valeur non pris en charge dans un objet partagé ou une collection partagée)
    • elle accepte l'ajout de nouvelles entités, c'est-à-dire qu'elle prend en charge la fonction entitySelection.add( ).

La nature partageable ou altérable d'une sélection d'entité est définie lors de la création de la sélection d'entité (elle ne peut pas être modifiée par la suite). Vous pouvez connaître la nature d'une sélection d'entité à l'aide de la fonction entitySelection.isAlterable( ) ou de la commande OB Est partage.

Une nouvelle sélection d'entité peut être partageable dans les cas suivants :

  • la nouvelle sélection d'entité résulte d'une fonction de classe ORDA appliquée à une dataClass: dataClass.all( ), dataClass.fromCollection( ), dataClass.query( ),
  • la nouvelle sélection d'entité est basée sur une relation entity.{nomAttribut} (par exemple company.employees) lorsque attributeName est un attribut lié à un-à-plusieurs et que l'entité n'appartient pas à une sélection d'entité.
  • la nouvelle sélection d'entité est explicitement copiée comme partageable avec entitySelection.copy( ) ou OB Copier (c'est-à-dire avec l'option ck shared).

Example: 

 $myComp:=ds.Company.get(2) //$myComp n'appartient pas à une sélection d'entité
 $employees:=$myComp.employees //$employees est partageable

Une nouvelle sélection d'entité est altérable dans les cas suivants :

Exemple :

 $toModify:=ds.Company.all().copy() //$toModify est altérable

Une nouvelle sélection d'entité hérite de la nature de la sélection d'entité d'origine dans les cas suivants :

  • la nouvelle sélection d'entité résulte de l'une des différentes fonctions de classe ORDA appliquées à une sélection d'entité existante (entitySelection.query( ), entitySelection.slice( ), etc.
  • la nouvelle sélection d'entité est basée sur une relation :
    • entity.{nomAttribut} (par exemple, company.employees) lorsque attributeName est un attribut relié 1 vers N et que l'entité appartient à une sélection d'entité (de même nature que la sélection d'entité entity.getSelection( ))
    • entitySelection.{nomAttribut} (par exemple, Employees.employer) lorsque attributeName est un attribut relié 1 vers N (de même nature que la sélection d'entité)
    • entitySelection.extract( ) lorsque la collection résultante contient des sélections d'entités (de même nature que la sélection d'entité)

Exemples :

 $highSal:=ds.Employee.query("salary >= :1";1000000)  //$highSal est partageable en raison de la requête sur dataClass
 $comp:=$highSal.employer //$comp est partageable car $highSal est partageable</p> <p>
 $lowSal:=ds.Employee.query("salary <= :1";10000).copy() 
  //$lowSal est altérable en raison de copy()
 $comp2:=$lowSal.employer //$comp2 est altérable car $lowSal est altérable

Note de compatibilité : Il est possible de "forcer" toutes les nouvelles sélections d'entités à être altérables par défaut dans votre projet à l'aide de la méthode dataStore.makeSelectionsAlterable( ). Ce paramètre de compatibilité n'est pas recommandé pour les nouveaux projets.

Vous travaillez avec deux sélections d'entités que vous souhaitez passer à un process de worker pour que celui-ci puisse envoyer des e-mails aux destinataires appropriés :

 var $paid;$unpaid : cs.InvoicesSelection
  //Nous obtenons des sélections d'entité pour les factures payées et impayées
 $paid:=ds.Invoices.query("status=:1";"Paid")
 $unpaid:=ds.Invoices.query("status=:1";"Unpaid")
 
  //passer des références de sélections d'entité comme paramètres au worker
 APPELER WORKER("mailing";"sendMails";$paid;$unpaid)

Méthode sendMails :

 #DECLARE($paid cs.InvoicesSelection;$unpaid cs.InvoicesSelection)
 var $invoice : cs.InvoicesEntity
 
 var $server;$transporter;$email;$status : Object
 
  //Preparer les e-mails
 $server:=Creer objet
 $server.host:="exchange.company.com"
 $server.user:="myName@company.com"
 $server.password:="my!!password"
 $transporter:=SMTP Creer transporteur($server)
 $email:=Creer objet
 $email.from:="myName@company.com"
 
  //Boucle sur les sélections d'entité
 Pour chaque($invoice;$unpaid)
    $email.to:=$invoice.customer.address // adresse e-mail du client
    $email.subject:="Payment OK for invoice # "+Chaine($invoice.number)
    $status:=$transporter.send($email)
 Fin de chaque
 
 Pour chaque($invoice;$unpaid)
    $email.to:=$invoice.customer.address // adresse e-mail du client
    $email.subject:="Please pay invoice # "+Chaine($invoice.number)
    $status:=$transporter.send($email)
 Fin de chaque

Les sélections d'entités locales peuvent être triées ou non-triées. Fondamentalement, les deux objets ont des fonctionnalités similaires, mais il existe des différences en termes de performances et de fonctionnalités disponibles. Vous pouvez décider du type de sélection d'entités à utiliser en fonction de vos besoins spécifiques.

Note : Les sélections d'entités suivantes sont toujours triées: 

  • sélections d'entités retournées par 4D Server vers un client distant
  • sélections d'entités fondées sur des datastores distants.
 
 

  • Les sélections d'entités non-ordonnées sont construites sur des bit tables en mémoire. Une sélection d'entités non-triées contient un bit pour chaque entité de la dataclass, indépendamment du fait que l'entité soit réellement ou pas dans la sélection. Chaque bit est égal à 1 ou 0, pour indiquer si l'entité est incluse ou non dans la sélection. C'est une représentation très compacte pour chaque entité.
    Par conséquent, les opérations utilisant des sélections d'entités non ordonnées sont très rapides. De plus, les sélections d'entités non ordonnées sont très économiques en terme d'espace mémoire. La taille d'une sélection d'entités non ordonnées, en octets, est toujours égale au nombre total d'entités de la dataclass divisé par 8. Par exemple, si vous créez une sélection d'entités non ordonnées pour une dataclass contenant 10 000 entités, elle occupera 1 250 octets, ce qui représente environ 1,2 Ko en RAM.
    D'un autre côté, les sélections d'entités non ordonnées ne peuvent pas être triées. Vous ne pouvez pas compter sur la position des entités dans la sélection. En outre, vous ne pouvez pas avoir plus d'une référence à la même entité dans la sélection : chaque entité ne peut être ajoutée qu'une seule fois.
  • Les sélections d'entités ordonnées sont construites sur des tableaux Entier long (contenant des références d'entités) en mémoire. Chaque référence à une entité prend 4 octets en mémoire. Le traitement et la maintenance de ces sélections prennent plus de temps et nécessitent plus d'espace mémoire que les sélections non-triées.
    D'un autre côté, elles peuvent être triées ou réorganisées, et vous pouvez compter sur des positions d'entités. En outre, vous pouvez ajouter plusieurs références à la même entité.

Le tableau suivant résume les principales caractéristiques de chaque type de sélection d'entités :

FonctionnalitéSélection d'entités non-triéeSélection d'entités triée
Vitesse de traitementtrès rapideplus lent
Taille en mémoiretrès petiteplus grande
Peut contenir plusieurs références à une entiténonoui

Pour des raisons d'optimisation, par défaut, 4D ORDA crée généralement des sélections d'entités non-ordonnées, sauf lorsque vous utilisez la méthode orderBy( ) ou si vous utilisez les options appropriées (voir ci-dessous). Dans cette documentation, sauf indication contraire, "sélection d'entités" fait généralement réféernce à une "sélection d'entités non-ordonnée".

 
 

Comme mentionné ci-dessus, par défaut, ORDA crée et gère les sélections d'entités non-ordonnées à la suite d'opérations telles que des requêtes ou des comparaisons comme and( ). Les sélections d'entités ordonnées sont créées uniquement lorsque cela est nécessaire ou lorsqu'elles sont spécifiquement demandées à l'aide d'options.

Les sélections d'entités triées sont créées dans les cas suivants :

  • résultat d'un orderBy( ) sur une sélection (de n'importe quel type) ou un orderBy( ) sur une dataclass,
  • résultat de la méthode newSelection( ) avec l'option dk keep ordered.

Les sélections d'entités non-triées sont créées dans les cas suivants :

  • résultat d'un query( ) standard sur une sélection (de n'importe quel type) ou un query( ) sur une dataclass,
  • résultat de la méthode newSelection( ) sans option,
  • résultat de l'une des méthodes de comparaison, quel que soit le type de sélection saisi : or( ), and( ), minus( ).

Notez que lorsqu'une sélection d'entités ordonnée devient une sélection non-ordonnée, toute référence d'entité répétée est supprimée.

Si vous voulez transformer une sélection d'entités ordonnée en une sélection non-ordonnée, vous pouvez simplement lui appliquer une opération and( ), par exemple :

  //mySel est une sélection d'entités ordonnée
 mySel:=mySel.and(mySel)
  //mySel est maintenant une sélection d'entités non-ordonnée

4D optimise automatiquement les requêtes ORDA qui utilisent des sélections d'entités ou qui chargent des entités en configuration client/serveur. Cette optimisation accélère l'exécution de votre application 4D en réduisant considérablement le volume d'informations transmises sur le réseau.

Les mécanismes d'optimisation suivants sont mis en oeuvre :

  • Lorsqu'un client demande une sélection d'entités au serveur, 4D "apprend" automatiquement les attributs de la sélection d'entités qui sont utilisés côté client lors de l'exécution du code et génère un "contexte d'optimisation". Ce contexte est relié à la sélection d'entités et stocke les attributs utilisés. Il sera mis à jour dynamiquement si d'autres attributs sont utilisés ultérieurement.
  • Les requêtes ultérieures qui sont envoyées au serveur à la même sélection d'entités réutilisent automatiquement le contexte d'optimisation et lisent uniquement les attributs nécessaires depuis le serveur, ce qui accélère le traitement. Par exemple, dans une listbox basée sur une sélection d'entités, la phase d'apprentissage a lieu durant l'affichage des premières lignes et l'affichage des lignes suivantes est fortement optimisé.
  • Un contexte d'optimisation existant peut être passé comme propriété à une autre sélection d'entités de la même dataclass, ce qui perment d'éviter la phase d'apprentissage et d'accélérer l'application (voir "Utilisation de la propriété context" ci-dessous).

Les méthodes suivantes associent automatiquement le contexte d'optimisation de la sélection d'entités d'origine à la sélection d'entités retournée :

Exemple

Considérons le code suivant :

 $sel:=$ds.Employee.query("firstname = ab@")
 Pour chaque($e;$sel)
    $s:=$e.firstname+" "+$e.lastname+" works for "+$e.employer.name // $e.employer renvoie à la table Company
 Fin de chaque

Grâce à l'optimisation, cette requête récupérera uniquement les données issues des attributs utilisés (firstname, lastname, employer, employer.name) dans $sel après la phase d'apprentissage. 

 

Utilisation de la propriété context

Vous pouvez tirer un meilleur parti de l'optimisation en utilisant la propriété context. Cette propriété référence un contexte d'optimisation "appris" pour une sélection d'entités. Elle peut être passée comme paramètre aux méthodes ORDA qui retournent de nouvelles sélections d'entités, afin que les sélections d'entités demandent directement au serveur les attributs utilisés, sans passer par la phase d'apprentissage.

Une même propriété de contexte d'optimisation peut être passée à un nombre illimité de sélections d'entités de la même dataclass. Toutes les méthodes ORDA qui gèrent les sélections d'entités prennent en charge la propriété context (par exemple les méthodes dataClass.query( ) ou dataClass.all( )). Il est toutefois important de garder à l'esprit qu'un contexte est automatiquement mis à jour lorsque de nouveaux attributs sont utilisés dans d'autres parties du code. Si le même contexte est réutilisé dans différents codes, il risque d'être surchargé et de perdre en efficacité.

Note : Un mécanisme similaire est mis en place pour des entités qui sont chargées, afin que seuls les attributs utilisés soient demandés (voir la méthode dataClass.get( )). 

Exemple avec la méthode dataClass.query( ) :

 C_OBJET($sel1;$sel2;$sel3;$sel4;$querysettings;$querysettings2)
 C_COLLECTION($data)
 $querysettings:=Creer objet("context";"shortList")
 $querysettings2:=Creer objet("context";"longList")
 
 $sel1:=ds.Employee.query("lastname = S@";$querysettings)
 $data:=extractData($sel1// Dans la méthode extractData, une optimisation est déclenchée et associée au contexte "shortList"
 
 $sel2:=ds.Employee.query("lastname = Sm@";$querysettings)
 $data:=extractData($sel2// Dans la méthode extractData, l'optimisation associée au contexte "shortList" est appliquée
 
 $sel3:=ds.Employee.query("lastname = Smith";$querysettings2)
 $data:=extractDetailedData($sel3// Dans la méthode extractDetailedData, une optimisation est déclenchée et associée au contexte "longList"
 
 $sel4:=ds.Employee.query("lastname = Brown";$querysettings2)
 $data:=extractDetailedData($sel4// Dans la méthode extractDetailedData, l'optimisation associée au contexte "longList" est appliquée

Listbox basée sur une sélection d'entités

L'optimisation d'une sélection d'entités s'applique automatiquement aux listbox basées sur une sélection d'entités dans les configurations client/serveur, au moment d'afficher et de dérouler le contenu d'une listbox : seuls les attributs affichés dans la listbox sont demandés depuis le serveur.
Un contexte spécifique nommé "mode page" est également proposé lorsque l'entité courante de la sélection est chargée à l'aide de l'expression Élément courant de la listbox (voir List box type collection ou entity selection). Cette fonctionnalité vous permet de ne pas surcharger le contexte initial de la listbox dans ce cas précis, notamment si la "page" requiert des attributs supplémentaires. A noter que seule l'utilisation de l'expression Élément courant permettra de créer/utiliser le contexte de la page (l'accès via entitySelection[index] modifiera le contexte de la sélection d'entité).
Cette optimisation sera également prise en charge par les requêtes ultérieures envoyées au serveur via les méthodes de navigation des entités. Les méthodes suivantes associeront automatiquement le contexte d'optimisation de l'entité source à l'entité retournée :

Par exemple, le code ci-dessous charge l'entité sélectionnée et permet de naviguer dans la sélection d'entités. Les entités sont chargées dans un contexte séparé et le contexte initial de la listbox demeure inchangé :

 $myEntity:=Form.currentElement // expression de l'élément courant
  //... faire quelque chose
 $myEntity:=$myEntity.next() //charge la prochaine entité à l'aide du même contexte

 

Note de compatibilité : Les contextes gérés dans les connexions établies par Ouvrir datastore ne peuvent être utilisés qu'entre des versions main similaires de 4D. Par exemple, une application distante 4D v19.x ne peut utiliser que les contextes d'un datastore 4D Server v19.x.

L'objet sélection d'entités lui-même ne peut pas être copié en tant qu'objet :

 $myentitysel:=OB Copier(ds.Employee.all()) //retourne null

Les propriétés des sélections d'entités sont toutefois énumérables :

 TABLEAU TEXTE($prop;0)
 OB LIRE NOMS PROPRIETES(ds.Employee.all();$prop)
  //$prop contient les noms des propriétés des sélections d'entités
  //("length", "00", "01"...)

 
PROPRIÉTÉS 

Produit : 4D
Thème : ORDA
Nom intl. : Entity selections

 
PAGE CONTENTS 
 
HISTORIQUE 

Créé : 4D v17
Modifié : 4D v18 R5

 
UTILISATION DE L'ARTICLE

4D - Mode Développement ( 4D v19)