# OrphanRemovalOnUpdate.java

    package org.codefilarete.stalactite.engine.configurer.onetoone;

    import java.util.ArrayList;
    import java.util.List;

    import org.codefilarete.reflection.Accessor;
    import org.codefilarete.stalactite.engine.listener.UpdateListener;
    import org.codefilarete.stalactite.engine.runtime.ConfiguredPersister;
    import org.codefilarete.tool.Duo;

    public class OrphanRemovalOnUpdate<SRC, TRGT> implements UpdateListener<SRC> {

    	private final ConfiguredPersister<TRGT, ?> targetPersister;
    	private final Accessor<SRC, TRGT> targetAccessor;
    	private final Accessor<TRGT, ?> targetIdAccessor;

    	public OrphanRemovalOnUpdate(ConfiguredPersister<TRGT, ?> targetPersister, Accessor<SRC, TRGT> targetAccessor) {
    		this.targetPersister = targetPersister;
    		this.targetAccessor = targetAccessor;
    		this.targetIdAccessor = targetPersister.getMapping().getIdMapping().getIdAccessor()::getId;
    	}

    	@Override
    	public void afterUpdate(Iterable<? extends Duo<SRC, SRC>> payloads, boolean allColumnsStatement) {
    		List<TRGT> targetsToDeleteUpdate = new ArrayList<>();
    		payloads.forEach(duo -> {
    			TRGT newTarget = getTarget(duo.getLeft());
    			TRGT oldTarget = getTarget(duo.getRight());
    			// nullified relations and changed ones must be removed (orphan removal)
    			// TODO: one day we'll have to cover case of reused instance in same graph : one of the relation must handle it, not both,
    			//  "else a marked instance" system must be implemented
    			if (oldTarget != null &&
    				(newTarget == null || !targetIdAccessor.get(newTarget).equals(targetIdAccessor.get(oldTarget)))) {
    					targetsToDeleteUpdate.add(oldTarget);
    			}
    		});
    		targetPersister.delete(targetsToDeleteUpdate);
    	}

    	private TRGT getTarget(SRC src) {
    		return src == null ? null : targetAccessor.get(src);
    	}
    }