Question Maxime LACH · Mars 20, 2024

Comment comparer deux Registered Object

J'aimerai comparer deux "Registered Object" et lister chaque propriété différente

Pour le moment j'ai ce code :

ClassMethod AssertObjectEquals(object As %RegisteredObject, objectToCompare As %RegisteredObject, Output msg As %String) As %Status
{
        Set returnValue = 1
        // check if same class
        Set className = $CLASSNAME(object)
        If (className '= $CLASSNAME(objectToCompare)) {
                Set returnValue = 0
                Set difference = "not same class"
        }

        If (returnValue) {
                // Get the definition to browse properties
                Set classDef = ##class(%Library.ClassDefinition).%OpenId(className)
                Set propertiesDef = classDef.Properties
                // Check the value for each property
                Set difference = ""
                For i = 1:1:propertiesDef.Count() {
                        Set propertyName = propertiesDef.GetAt(i).Name
                        Set propertyValue = $PROPERTY(object,propertyName)
                        // if different, supply the variable difference with the name of property + value
                        If ((propertyValue '= "") && (propertyValue '= $PROPERTY(objectToCompare,propertyName)))
                        {
                                Set difference = difference _ "; " _ propertyName _ " = " _ propertyValue
                        }
                }
        }
        if difference = ""
                {Set msg = "equal"}
        else {
                Set msg = difference
        }
        Return $$$OK
}

Mais cela ne prend pas en compte les propriétés complexes telles que les listes, les tableaux ou les objets.
Quelqu’un a-t-il une idée pour compléter la méthode de classe ou une autre solution totalement différente ?
Merci d’avance !

Comments

DC AI Bot · Mai 25 Bot

Oui : une approche proposée consiste à rendre la comparaison récursive pour traiter aussi les propriétés objets et les collections. Le principe est : vérifier d’abord que les deux objets sont de la même classe, parcourir les propriétés via %Library.ClassDefinition, puis :

  • si la propriété est un objet, rappeler la méthode de comparaison ;
  • si l’objet étend %Collection.Super, parcourir ses éléments avec Count() et GetAt(ii) puis comparer chaque élément ;
  • sinon, pour les valeurs simples, enregistrer les différences quand les valeurs sont distinctes. [1]

Exemple fourni : [1]

ClassMethod CompareObjects(expectedObject As %RegisteredObject, actualObject As %RegisteredObject) As %Status
{
    Set status= $$$OK
    Set returnValue = 1
    Try{
        // check if same class
        Set className = $CLASSNAME(expectedObject)
        If (className '= $CLASSNAME(actualObject)) {
            Set returnValue = 0
            Set ^||differences(expectedObject,actualObject) = "not same class"
        }
        If (returnValue) {
            // Get the definition to browse properties
            Set classDef = ##class(%Library.ClassDefinition).%OpenId(className)
            Set propertiesDef = classDef.Properties
            // Check the value for each property
            For i = 1:1:propertiesDef.Count() {
                Set propertyName = propertiesDef.GetAt(i).Name
                Set propertyValueExpected = $PROPERTY(expectedObject,propertyName)
                Set propertyValueActual=$PROPERTY(actualObject,propertyName)
                // if different, supply the variable difference with the name of property + value
                If $ISOBJECT(propertyValueExpected){
                    If propertyValueExpected.%Extends("%Collection.Super"){
                        For ii=1:1:propertyValueExpected.Count(){
                            Set tSC= ..CompareObjects(propertyValueExpected.GetAt(ii),propertyValueActual.GetAt(ii))
                        }
                    }
                    Else{
                        Set tSC= ..CompareObjects(propertyValueExpected,propertyValueActual)
                    }
                }
                Else{
                    If ((propertyValueExpected '= "") && (propertyValueExpected '= propertyValueActual)) {
                        Set ^||differences(expectedObject,propertyName)=propertyValueExpected _ " != " _ propertyValueActual
                    }
                }
            }
        }
    }Catch e{
        Set status=e.AsStatus()
    }
    Quit status
}

Pour restituer les écarts, l’exemple associé appelle ensuite CompareObjects, teste l’existence de ^||differences, puis construit un message en parcourant ce global temporaire. [1]

Pour les listes ObjectScript, il existe aussi un exemple séparé qui calcule les éléments ajoutés et supprimés entre deux %List en utilisant $LISTVALID, $LISTLENGTH, $LISTFIND et en retournant added / deleted. Cela peut être utile si certaines de vos propriétés sont des listes sérialisées plutôt que des objets de collection. [2]

Le même fil souligne aussi qu’avant de comparer des collections, il faut définir la règle métier : faut-il tenir compte de l’ordre ou non ? Deux collections contenant les mêmes valeurs dans un ordre différent peuvent être considérées soit identiques, soit différentes selon le cas d’usage. [2]

Si vous voulez fiabiliser encore votre méthode de parcours des propriétés, une autre source montre plusieurs façons d’énumérer les propriétés d’une classe, y compris héritées, notamment via %Dictionary.CompiledProperty ou %Dictionary.CompiledClass. [3]

En résumé, la solution la plus proche de votre besoin est de transformer votre méthode en comparaison récursive objet/collection, comme dans l’exemple ci-dessus. Pour les listes simples, vous pouvez compléter avec une logique spécialisée de diff de %List. [1][2][3]


Sources:

Dites-nous en plus:
Je n'aime pas le style
Pas factuellement correct
N'a pas entièrement suivi les instructions
A refusé alors qu'elle n'aurait pas dû le faire
Est fainéante
Plus...
Envoyer
0 0