Comparing two objects and showing the changed attributes

0
I will try to explain my use case through an example: Lets assume a Person object which is changed by mutations I receive. The mutation contains two Person objects, the old and the new one. The new one will simply overwrite the old one. The mutations are stored and should contain the information about the attributes which are changed, something like: attribute name | old value | new value age | 30 | 31 surname | Smit | Smith I was thinking about an entity ChangedAttribute in which I store the name, old value and new value so I can easily display them. Of course I can check each attribute when I process the mutation and create the ChangedAttribute objects, but I need a more generic solution. The only thing I could think of was a Java action which takes two objects as input, do some reflection magic to iterate over the attributes of the objects, compare them and return a list of ChangedAttribute objects. Since I'm not that eager to create this I was wondering if there were any existing solutions which I can use or use as example.  Or are there better ways to handle this in Mendix?
asked
3 answers
1

Hi Stefan,

You are definitely on the right track with the ChangedAttribute object and the java action. But you don't really need reflection to implement this because Mendix provides user friendly ways to inspect the object's attributes.

To start get a list of attributes by invoking
`oldObject.getMembers()` - https://apidocs.mendix.com/7/runtime/com/mendix/systemwideinterfaces/core/IMendixObject.html#getMembers-com.mendix.systemwideinterfaces.core.IContext

Afterwards iterate over all the members and get the value by using `member.parseValueToString()` or `member.getValue().toString()` - https://apidocs.mendix.com/7/runtime/com/mendix/systemwideinterfaces/core/IMendixObjectMember.html#parseValueToString-com.mendix.systemwideinterfaces.core.IContext-

I would encourage you to try and build this on your own it really is not that much code and is a good excercise to expand your knowledge of the Mendix runtime.

Hope this helps,
-Andrej

answered
1

This existing solution you're looking for is the audit trail module, which does pretty much exactly what you describe.

answered
1

I finally found some time to make the java action, for reference purposes I will add it here. Feel free to comment.

 

		IContext context = Core.createSystemContext();
		SimpleDateFormat sdf = new SimpleDateFormat();
		List<IMendixObject> result = new ArrayList<IMendixObject>();
		
		//get all the members of the old object
		Map<String, ? extends IMendixObjectMember<?>> map = OldObject.getMembers(context);
				
		for(Entry<String, ? extends IMendixObjectMember<?>> e : map.entrySet()) {
			
			IMendixObjectMember<?> oldMember = e.getValue();
			
			if(oldMember instanceof MendixObjectReference || oldMember instanceof MendixObjectReferenceSet) {
				//ignore associations
				continue;
			}
			
			String memberName = e.getKey();
			IMendixObjectMember<?> newMember = NewObject.getMember(context, memberName);

			String newValue = newMember.parseValueToString(context);
			String oldValue = oldMember.parseValueToString(context);					
			
			//changed?
			if(!oldValue.equals(newValue)) {	
				
				//create new mendix object
				IMendixObject myEntity = Core.instantiate(context, ChangedItem.entityName.toString());
				myEntity.setValue(context,  ChangedItem.MemberNames.Name.toString(), memberName);
				
				//format dates
				if(oldMember instanceof MendixDateTime) {
					Date date = ((MendixDateTime)oldMember).getValue(context);
					if(date != null) {
						oldValue = sdf.format(date);						
					}
					date = ((MendixDateTime)newMember).getValue(context);
					if(date != null) { 
						newValue = sdf.format(date);						
					}
				}
				
				myEntity.setValue(context,  ChangedItem.MemberNames.OldValue.toString(), oldValue);
				myEntity.setValue(context,  ChangedItem.MemberNames.NewValue.toString(), newValue);
				result.add(myEntity);
				
				//save
				Core.commit(context, myEntity);
			}
		}		
		
		return result;

 

answered