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
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 avecCount()etGetAt(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: