changeset 134:25bfcc9d757c

effort to re-use more relations when saving entities. new replaceMultipleSourceRelations() and changes to use it. changes for renamed replaceUniqueSourceRelation().
author casties
date Fri, 24 Feb 2017 20:25:33 +0100
parents 5ccd6e709f95
children 0183b8a09717
files src/main/java/de/mpiwg/itgroup/ismi/entry/beans/AbstractISMIBean.java src/main/java/de/mpiwg/itgroup/ismi/entry/beans/CurrentCityBean.java src/main/java/de/mpiwg/itgroup/ismi/entry/beans/CurrentCodexBean.java src/main/java/de/mpiwg/itgroup/ismi/entry/beans/CurrentCollectionBean.java src/main/java/de/mpiwg/itgroup/ismi/entry/beans/CurrentDigitalizationBean.java src/main/java/de/mpiwg/itgroup/ismi/entry/beans/CurrentPersonBean.java src/main/java/de/mpiwg/itgroup/ismi/entry/beans/CurrentRepositoryBean.java src/main/java/de/mpiwg/itgroup/ismi/entry/beans/CurrentSubjectBean.java src/main/java/de/mpiwg/itgroup/ismi/entry/beans/CurrentTextBean.java src/main/java/de/mpiwg/itgroup/ismi/entry/beans/CurrentWitnessBean.java src/main/java/de/mpiwg/itgroup/ismi/event/beans/CopyEvent.java src/main/java/de/mpiwg/itgroup/ismi/event/beans/StudyEvent.java src/main/java/de/mpiwg/itgroup/ismi/event/beans/TransferEvent.java src/main/java/de/mpiwg/itgroup/ismi/merge/ImportMerge.java src/main/webapp/entry/codex.xhtml
diffstat 15 files changed, 232 insertions(+), 238 deletions(-) [+]
line wrap: on
line diff
--- a/src/main/java/de/mpiwg/itgroup/ismi/entry/beans/AbstractISMIBean.java	Thu Feb 23 19:25:37 2017 +0100
+++ b/src/main/java/de/mpiwg/itgroup/ismi/entry/beans/AbstractISMIBean.java	Fri Feb 24 20:25:33 2017 +0100
@@ -76,6 +76,8 @@
 	
 	public static String rel_was_created_by = "was_created_by";
 	public static String rel_was_copied_by = "was_copied_by";
+	public static String rel_was_copied_in = "was_copied_in";
+	public static String rel_was_copied_in_as = "was_copied_in_as";
 	public static String is_exemplar_of = "is_exemplar_of";
 	public static String is_possible_exemplar_of = "is_possible_exemplar_of";
 	public static String rel_had_patron = "had_patron";
@@ -294,15 +296,19 @@
 	 */
 	protected void prepareEndNoteRefs2Save() throws Exception {
 		//REFERENCE -> is_reference_of -> WITNESS
+		List<Entity> refs = new ArrayList<Entity>();
 		this.entity.removeAllTargetRelationsByName(rel_is_reference_of);
 		for (SelectableObject<Reference> so : this.endNoteRefTable.list) {
 			Reference ref = so.getObj();
-			Entity entRef = ref.getEnt();
-			getWrapper().saveEntity(entRef, getUserName(), Reference.editReferenceIntent);
-			//entity can be no persistent, therefore the assignment of the relation should be done after the save
-			entRef.addSourceRelation(rel_is_reference_of, entity);
-			//new Relation(entRef, entity, rel_is_reference_of);
+			Entity ent = ref.getEnt();
+			if (!ent.isPersistent()) {
+				// persist reference Entity
+				getWrapper().saveEntity(ent, getUserName(), Reference.editReferenceIntent);
+			}
+			refs.add(ent);
 		}
+		// update relations
+		this.replaceMultipleTargetRelations(entity, refs, REFERENCE, rel_is_reference_of);
 	}
 	
 
@@ -1072,7 +1078,7 @@
 	}
 
     /**
-     * Replace the given source relations on the given entity by the contents of the AliasListenerObject 
+     * Replace all source relations on the given entity by the contents of the AliasListenerObject 
      * (type entClass) using the given relName and aliasRelName.
      * 
      * ent - relName -> targetClass,
@@ -1084,24 +1090,121 @@
      * @param relName
      * @param aliasRelName
      */
-    protected void replaceAliasSourceRelation(Entity ent, AliasListenerObject lo, String targetClass, String relName, String aliasRelName) {
+    protected void replaceUniqueAliasSourceRelation(Entity ent, AliasListenerObject lo, String targetClass, String relName, String aliasRelName) {
         Entity target = lo.entity;
         if (target == null || target.getObjectClass() == null) {
             return;
         }
         if (target.getObjectClass().equals(targetClass)) {
             // regular target entity e.g. PLACE
-            ent.replaceSourceRelation(target, targetClass, relName);
+            ent.replaceUniqueSourceRelation(target, targetClass, relName);
             ent.removeAllSourceRelationsByName(aliasRelName);
         } else if (target.getObjectClass().equals(ALIAS)) {
             // e.g. WITNESS -> was_created_in_as -> ALIAS
-            ent.replaceSourceRelation(target, ALIAS, aliasRelName);
+            ent.replaceUniqueSourceRelation(target, ALIAS, aliasRelName);
             // ALIAS -> is_alias_name_of -> PLACE
             List<Entity> places = getWrapper().getTargetsForSourceRelation(target, is_alias_name_of, targetClass, 1);
             if (! places.isEmpty()) {
                 // e.g. WITNESS -> was_created_in -> PLACE
-                ent.replaceSourceRelation(places.get(0), targetClass, relName);
+                ent.replaceUniqueSourceRelation(places.get(0), targetClass, relName);
             }
         }
     }
+    
+	/**
+	 * Replaces all source relations of the given type on the given entity with the given targets.
+	 * 
+	 * @param ent
+	 * @param newTars
+	 * @param tarObjClass
+	 * @param relName
+	 */
+	public void replaceMultipleSourceRelations(Entity ent, List<Entity> newTars, String tarObjClass, String relName) {
+		if (ent.isLightweight()) {
+			ent = getWrapper().getEntityContent(ent);
+		}
+		if (newTars == null || newTars.isEmpty()) {
+			// no new target -> remove all relations of this type
+			ent.removeAllSourceRelations(relName, tarObjClass);
+			return;
+		}
+		
+		ArrayList<Relation> oldRelations = new ArrayList<Relation>(ent.getSourceRelations(relName, tarObjClass));
+		List<Long> newTarIds = new ArrayList<Long>();
+		// check new targets
+		for (Entity tar : newTars) {
+			if (tar.isLightweight()) {
+				tar = getWrapper().getEntityContent(tar);
+			}
+			Long tarId = tar.getId();
+			newTarIds.add(tarId);
+			if (ent.containsSourceRelation(relName, tarId)) {
+				// relation exists
+				oldRelations.remove(ent.getSourceRelation(relName, tarId));
+			} else {
+				// new relation
+				ent.addSourceRelation(relName, tar);
+			}
+		}
+		
+		// check remaining old relations
+		for (Relation oldRel : oldRelations) {
+			Long tarId = oldRel.getTargetId();
+			if (newTarIds.contains(tarId)) {
+				// this should not happen
+				logger.error("Old relation to new target ID:"+oldRel);
+			} else {
+				ent.removeSourceRelation(relName, oldRel.getTargetId());
+			}
+		}
+	}
+	
+	/**
+	 * Replaces all target relations of the given type on the given entity with the given sources.
+	 * 
+	 * @param ent
+	 * @param newSrcs
+	 * @param srcObjClass
+	 * @param relName
+	 */
+	public void replaceMultipleTargetRelations(Entity ent, List<Entity> newSrcs, String srcObjClass, String relName) {
+		if (ent.isLightweight()) {
+			ent = getWrapper().getEntityContent(ent);
+		}
+		if (newSrcs == null || newSrcs.isEmpty()) {
+			// no new target -> remove all relations of this type
+			ent.removeAllTargetRelations(relName, srcObjClass);
+			return;
+		}
+		
+		ArrayList<Relation> oldRelations = new ArrayList<Relation>(ent.getTargetRelations(relName, srcObjClass));
+		List<Long> newSrcIds = new ArrayList<Long>();
+		// check new targets
+		for (Entity src : newSrcs) {
+			if (src.isLightweight()) {
+				src = getWrapper().getEntityContent(src);
+			}
+			Long srcId = src.getId();
+			newSrcIds.add(srcId);
+			if (ent.containsTargetRelation(relName, srcId)) {
+				// relation exists
+				oldRelations.remove(ent.getTargetRelation(relName, srcId));
+			} else {
+				// new relation
+				ent.addTargetRelation(relName, src);
+			}
+		}
+		
+		// check remaining old relations
+		for (Relation oldRel : oldRelations) {
+			Long srcId = oldRel.getSourceId();
+			if (newSrcIds.contains(srcId)) {
+				// this should not happen
+				logger.error("Old relation to new source ID:"+oldRel);
+			} else {
+				ent.removeTargetRelation(relName, oldRel.getTargetId());
+			}
+		}
+	}
+	
 }
--- a/src/main/java/de/mpiwg/itgroup/ismi/entry/beans/CurrentCityBean.java	Thu Feb 23 19:25:37 2017 +0100
+++ b/src/main/java/de/mpiwg/itgroup/ismi/entry/beans/CurrentCityBean.java	Fri Feb 24 20:25:33 2017 +0100
@@ -12,7 +12,6 @@
 import org.mpi.openmind.repository.bo.Attribute;
 import org.mpi.openmind.repository.bo.Entity;
 import org.mpi.openmind.repository.bo.Node;
-import org.mpi.openmind.repository.bo.Relation;
 import org.mpi.openmind.repository.services.utils.EditIntent;
 
 import de.mpiwg.itgroup.ismi.auxObjects.ListenerObject;
@@ -154,13 +153,16 @@
 				return "SAVE_ERROR";
 			}
 			
-			this.entity.replaceSourceRelation(this.getCountryLo().entity, PLACE, is_part_of);
-						
-			this.entity.removeAllTargetRelationsByName(is_part_of);
+			// (this) PLACE -> is_part_of -> (other) PLACE
+			this.entity.replaceUniqueSourceRelation(this.getCountryLo().entity, PLACE, is_part_of);
+			
+			// (other) PLACE -> is_part_of -> (this) PLACE
+			ArrayList<Entity> subPlaces = new ArrayList<Entity>();
 			for(SelectableObject<Entity> so : this.placesPartOfThis){
 				Entity place = getWrapper().getEntityByIdWithContent(so.getObj().getId());
-				new Relation(place, this.entity, is_part_of);
+				subPlaces.add(place);
 			}
+			replaceMultipleTargetRelations(entity, subPlaces, PLACE, is_part_of);
 			
 			/*
 			this.entity.removeAllTargetRelationsByName(lived_in);
@@ -170,21 +172,15 @@
 			}
 			*/
 			
-            //ALIAS -> is_alias_name_of -> PERSON
-            this.entity.removeAllTargetRelationsByName(is_alias_name_of);
-            for(Entity alias : this.aliasList.getEntities()){
-                Entity alias0 = getWrapper().getEntityByIdWithContent(alias.getId());
-                new Relation(alias0, this.entity, is_alias_name_of);
-            }
+            // ALIAS -> is_alias_name_of -> PLACE
+			replaceMultipleTargetRelations(entity, aliasList.getEntities(), ALIAS, is_alias_name_of);
             
 			//REFERENCE -> is_reference_of -> THIS
 			this.prepareEndNoteRefs2Save();		
 			
-			if (this.isSelectedSaveAsNew()) {
-				this.setSelectedSaveAsNew(false);
-			} else {
-				this.entity = getWrapper().saveEntity(this.entity, getSessionUser().getEmail(), editPlaceIntent);
-			}
+			// save this entity
+			this.entity = getWrapper().saveEntity(this.entity, getSessionUser().getEmail(), editPlaceIntent);
+			
 			this.updateRelatedOW(this.entity, getSessionUser().getEmail());
 			this.setCurrentId(this.entity.getId().toString());
 			
--- a/src/main/java/de/mpiwg/itgroup/ismi/entry/beans/CurrentCodexBean.java	Thu Feb 23 19:25:37 2017 +0100
+++ b/src/main/java/de/mpiwg/itgroup/ismi/entry/beans/CurrentCodexBean.java	Fri Feb 24 20:25:33 2017 +0100
@@ -218,7 +218,7 @@
 			if(this.isAlias){
 				if(referencedCodexTemplate.getCodexLo().entity != null){
 					// CODEX -> is_part_of -> CODEX
-					this.entity.replaceSourceRelation(referencedCodexTemplate.getCodexLo().entity, CODEX, "is_alias_of");	
+					this.entity.replaceUniqueSourceRelation(referencedCodexTemplate.getCodexLo().entity, CODEX, "is_alias_of");	
 				}else{
 					this.entity.removeAllSourceRelations("is_alias_of", CODEX);
 				}			
@@ -242,7 +242,7 @@
 				return PAGE_EDITOR;
 			}
 
-			this.entity.replaceSourceRelation(this.getCollectionLo().entity, COLLECTION, is_part_of);
+			this.entity.replaceUniqueSourceRelation(this.getCollectionLo().entity, COLLECTION, is_part_of);
 			
 			// CODEX -> owner_by (manyToMany) -> PERSON
 			this.entity.removeAllSourceRelationsByName(owned_by);
@@ -253,33 +253,38 @@
 			//REFERENCE -> is_reference_of -> THIS
 			//this.entity = this.prepareReferencesToSave(this.entity);
 			this.prepareEndNoteRefs2Save();		
+
+			// CODEX -> owned_by -> PERSON
+			replaceMultipleSourceRelations(entity, ownedByPeople.getEntities(), PERSON, owned_by);
+			// CODEX -> read_by -> PERSON
+			replaceMultipleSourceRelations(entity, readByPeople.getEntities(), PERSON, "read_by");
 			
-			if (this.isSelectedSaveAsNew()) {
-				//this.entity = getWrapper().saveEntityAsNew(this.entity,getSessionUser().getEmail());
-				this.setSelectedSaveAsNew(false);
-			} else {
-				for (Entity owner : this.ownedByPeople.getEntities()) {
-					if (owner.isLightweight()) {
-						owner = getWrapper().getEntityByIdWithContent(owner.getId());
-					}
-					Relation ownerBy = new Relation(this.entity, owner, owned_by);
-					Calendar cal = ownedByPeople.getCalendar(owner.getId());
-					if (cal != null) {
-						ownerBy.addAttribute(new Attribute("date", "date", cal.toJSONString()));
-					}
+			/* TODO: currently ignoring date on relations
+			for (Entity owner : this.ownedByPeople.getEntities()) {
+				if (owner.isLightweight()) {
+					owner = getWrapper().getEntityByIdWithContent(owner.getId());
+				}
+				Relation ownerBy = new Relation(this.entity, owner, owned_by);
+				Calendar cal = ownedByPeople.getCalendar(owner.getId());
+				if (cal != null) {
+					ownerBy.addAttribute(new Attribute("date", "date", cal.toJSONString()));
 				}
-				for (Entity reader : this.readByPeople.getEntities()) {
-					Relation readBy = new Relation(this.entity, reader, "read_by");
-					Calendar cal = readByPeople.getCalendar(reader.getId());
-					if (cal != null) {
-						readBy.addAttribute(new Attribute("date", "date", cal.toJSONString()));
-					}
+			}
+			for (Entity reader : this.readByPeople.getEntities()) {
+				Relation readBy = new Relation(this.entity, reader, "read_by");
+				Calendar cal = readByPeople.getCalendar(reader.getId());
+				if (cal != null) {
+					readBy.addAttribute(new Attribute("date", "date", cal.toJSONString()));
 				}
+			}
+			*/
 
-				this.entity = getWrapper().saveEntity(this.entity, getSessionUser().getEmail(), editCodexIntent);
-			}
-
+			// save this entity
+			this.entity = getWrapper().saveEntity(this.entity, getSessionUser().getEmail(), editCodexIntent);
+			
+			// update own value of related objects (codex name in many names)
 			this.updateRelatedOW(this.entity, getSessionUser().getEmail());
+			
 			getSessionBean().setEditFormCurrentEntId(this.entity.getId());
 			
 			logger.info("Entity saved - Time = " + (System.currentTimeMillis() - start) + ", " + entity);
--- a/src/main/java/de/mpiwg/itgroup/ismi/entry/beans/CurrentCollectionBean.java	Thu Feb 23 19:25:37 2017 +0100
+++ b/src/main/java/de/mpiwg/itgroup/ismi/entry/beans/CurrentCollectionBean.java	Fri Feb 24 20:25:33 2017 +0100
@@ -113,11 +113,9 @@
 			this.entity = this.updateEntityAttributes(this.entity);
 			// checking is the identifier is unique for the selected collecion
 			Attribute attName = this.entity.getAttributeByName("name");
-			String collectionName = (attName == null) ? null : attName
-					.getValue();
+			String collectionName = (attName == null) ? null : attName.getValue();
 			if (StringUtils.isNotEmpty(collectionName)) {
-				if (!checkUnityCollection(collectionName,
-						(isSelectedSaveAsNew()) ? null : this.entity.getId(),
+				if (!checkUnityCollection(collectionName, (isSelectedSaveAsNew()) ? null : this.entity.getId(),
 						this.getRepositoryLo().entity)) {
 					this.renderUnityCheckerDialog();
 					this.setSelectedSaveAsNew(false);
@@ -133,22 +131,19 @@
 				return "";
 			}
 
-			if (this.getRepositoryLo().entity != null
-					&& this.getRepositoryLo().entity.isLightweight()) {
+			if (this.getRepositoryLo().entity != null && this.getRepositoryLo().entity.isLightweight()) {
 				this.getRepositoryLo().entity = getWrapper()
-						.getEntityByIdWithContent(
-								this.getRepositoryLo().entity.getId());
+						.getEntityByIdWithContent(this.getRepositoryLo().entity.getId());
 			}
-			this.entity.replaceSourceRelation(this.getRepositoryLo().entity,
-					REPOSITORY, is_part_of);
+			this.entity.replaceUniqueSourceRelation(this.getRepositoryLo().entity, REPOSITORY, is_part_of);
 
 			// REFERENCE -> is_reference_of -> THIS
 			this.prepareEndNoteRefs2Save();
 
 			if (isSelectedSaveAsNew()) {
-				//this.entity.removeAllTargetRelations(is_part_of, CODEX);
-				//this.entity = getWrapper().saveEntityAsNew(this.entity,
-				//		getSessionUser().getEmail());
+				// this.entity.removeAllTargetRelations(is_part_of, CODEX);
+				// this.entity = getWrapper().saveEntityAsNew(this.entity,
+				// getSessionUser().getEmail());
 			} else {
 				this.entity = getWrapper().saveEntity(this.entity, getSessionUser().getEmail(), editCollectionIntent);
 			}
@@ -156,8 +151,7 @@
 			this.updateRelatedOW(this.entity, getSessionUser().getEmail());
 			this.setCurrentId(this.entity.getId().toString());
 
-			logger.info("Entity saved - Time = "
-					+ (System.currentTimeMillis() - start) + ", " + entity);
+			logger.info("Entity saved - Time = " + (System.currentTimeMillis() - start) + ", " + entity);
 			this.printSuccessSavingEntity();
 
 			this.setSelectedSaveAsNew(false);
--- a/src/main/java/de/mpiwg/itgroup/ismi/entry/beans/CurrentDigitalizationBean.java	Thu Feb 23 19:25:37 2017 +0100
+++ b/src/main/java/de/mpiwg/itgroup/ismi/entry/beans/CurrentDigitalizationBean.java	Fri Feb 24 20:25:33 2017 +0100
@@ -88,8 +88,9 @@
 			this.entity = this.updateEntityAttributes(this.entity);
 
 			// DIGITALIZATION -> is_digitalization_of -> CODEX
-			this.entity.replaceSourceRelation(getCodexLo().entity, CODEX, is_digitalization_of);
+			this.entity.replaceUniqueSourceRelation(getCodexLo().entity, CODEX, is_digitalization_of);
 			
+			// save this entity
 			this.entity = getWrapper().saveEntity(this.entity, user.getEmail(), editDigitalizationIntent);
 			
 			this.setEntity(this.entity);
--- a/src/main/java/de/mpiwg/itgroup/ismi/entry/beans/CurrentPersonBean.java	Thu Feb 23 19:25:37 2017 +0100
+++ b/src/main/java/de/mpiwg/itgroup/ismi/entry/beans/CurrentPersonBean.java	Fri Feb 24 20:25:33 2017 +0100
@@ -1,6 +1,7 @@
 package de.mpiwg.itgroup.ismi.entry.beans;
 
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -265,17 +266,13 @@
 			this.entity = updateEntityAttributes(this.entity);
 
 			// PERSON -> was_born_in -> PLACE
-			replaceAliasSourceRelation(this.entity, birthPlaceLo, PLACE, "was_born_in", "was_born_in_as");            
+			replaceUniqueAliasSourceRelation(this.entity, birthPlaceLo, PLACE, "was_born_in", "was_born_in_as");            
             
             // PERSON -> was_died_in -> PLACE
-            replaceAliasSourceRelation(this.entity, deathPlaceLo, PLACE, "died_in", "died_in_as");            
+            replaceUniqueAliasSourceRelation(this.entity, deathPlaceLo, PLACE, "died_in", "died_in_as");            
 
 			// ALIAS -> is_alias_name_of -> PERSON
-			this.entity.removeAllTargetRelationsByName(is_alias_name_of);
-			for(Entity alias : this.aliasList.getEntities()){
-				Entity alias0 = getWrapper().getEntityByIdWithContent(alias.getId());
-				new Relation(alias0, this.entity, is_alias_name_of);
-			}
+			replaceMultipleTargetRelations(entity, aliasList.getEntities(), ALIAS, is_alias_name_of);
 			
             // ALIAS -> is_prime_alias_name_of/is_alias_name_of -> PERSON
 			this.entity.removeAllTargetRelationsByName(is_prime_alias_name_of);
@@ -288,7 +285,7 @@
 				}
 				shortNameAlias = getWrapper().saveEntity(shortNameAlias, getSessionUser().getEmail(), null);
 				// save as is_alias_name_of
-				new Relation(shortNameAlias, this.entity, is_alias_name_of);
+				entity.replaceUniqueTargetRelation(shortNameAlias, ALIAS, is_alias_name_of);
 			}
 			
 			// PERSON -> lived_in -> PLACE (manyToMany)
@@ -324,33 +321,26 @@
 			}
 			
 			// Person -> has_floruit_date -> FLORUIT DATE
-			this.entity.removeAllSourceRelationsByName(has_floruit_date);
-			for(Entity floruitDate : this.floruitList.getEntities()){
-				Entity floruitDate0 = getWrapper().getEntityByIdWithContent(floruitDate.getId());
+			ArrayList<Entity> floruitDates = new ArrayList<Entity>();
+			for (Entity floruitDate : this.floruitList.getEntities()) {
+				floruitDate = getWrapper().getEntityContent(floruitDate);
 				Calendar cal = floruitList.getCalendar(floruitDate.getId());
-				
-				if(floruitDate0.getAttributeByName("date") == null){
-					floruitDate0.addAttribute(new Attribute("date", "date", cal.toJSONString()));
-				}else{
-					floruitDate0.getAttributeByName("date").setValue(cal.toJSONString());
+
+				if (floruitDate.getAttributeByName("date") == null) {
+					floruitDate.addAttribute(new Attribute("date", "date", cal.toJSONString()));
+				} else {
+					floruitDate.getAttributeByName("date").setValue(cal.toJSONString());
 				}
-				getWrapper().saveAssertion(floruitDate0, getUserName());
-				new Relation(this.entity, floruitDate0, has_floruit_date);
+				getWrapper().saveEntity(floruitDate, getUserName(), null);
+				floruitDates.add(floruitDate);
 			}
+			replaceMultipleSourceRelations(entity, floruitDates, FLORUIT_DATE, has_floruit_date);
 			
 			//PERSON -> student of manyToMany -> PERSON
-			this.entity.removeAllSourceRelationsByName(was_student_of);
-			for(Entity teacher : this.studentOfList.getEntities()){
-				Entity teacher0 = getWrapper().getEntityByIdWithContent(teacher.getId()); 
-				new Relation(this.entity, teacher0, was_student_of);
-			}
+			replaceMultipleSourceRelations(entity, studentOfList.getEntities(), PERSON, was_student_of);
 			
 			//PERSON -> has_role -> ROLE
-			this.entity.removeAllSourceRelationsByName(has_role);
-			for(Entity role : this.roleList.getEntities()){
-				Entity role0 = getWrapper().getEntityByIdWithContent(role.getId());
-				new Relation(this.entity, role0, has_role);
-			}
+			replaceMultipleSourceRelations(entity, roleList.getEntities(), ROLE, has_role);
 			
 			//REFERENCE -> is_reference_of -> THIS
 			this.prepareEndNoteRefs2Save();
--- a/src/main/java/de/mpiwg/itgroup/ismi/entry/beans/CurrentRepositoryBean.java	Thu Feb 23 19:25:37 2017 +0100
+++ b/src/main/java/de/mpiwg/itgroup/ismi/entry/beans/CurrentRepositoryBean.java	Fri Feb 24 20:25:33 2017 +0100
@@ -101,7 +101,7 @@
 				return PAGE_EDITOR;
 			}
 			
-			this.entity.replaceSourceRelation(this.getCityLo().getEntity(), PLACE, is_in);
+			this.entity.replaceUniqueSourceRelation(this.getCityLo().getEntity(), PLACE, is_in);
 			
 			//REFERENCE -> is_reference_of -> THIS
 			this.prepareEndNoteRefs2Save();
--- a/src/main/java/de/mpiwg/itgroup/ismi/entry/beans/CurrentSubjectBean.java	Thu Feb 23 19:25:37 2017 +0100
+++ b/src/main/java/de/mpiwg/itgroup/ismi/entry/beans/CurrentSubjectBean.java	Fri Feb 24 20:25:33 2017 +0100
@@ -112,16 +112,18 @@
 			
 			this.entity = updateEntityAttributes(this.entity);
 			
-			this.entity.removeAllSourceRelations(is_part_of, SUBJECT);
 			if(getIdMainSubject() != null){
 				Entity mainCategory = getWrapper().getEntityById(getIdMainSubject());
 				//replaceSourceRelation(this.entity, mainCategory, SUBJECT, is_part_of);
 				if (mainCategory.isLightweight()) {
 					mainCategory = getWrapper().getEntityContent(mainCategory);
 				}
-				this.entity.replaceSourceRelation(mainCategory, SUBJECT, is_part_of);
+				this.entity.replaceUniqueSourceRelation(mainCategory, SUBJECT, is_part_of);
+			} else {
+				this.entity.removeAllSourceRelations(is_part_of, SUBJECT);
 			}
 			
+			// save this entity
 			this.entity = getWrapper().saveEntity(this.entity, user.getEmail(), editSubjectIntent);
 			getSessionBean().setEditFormCurrentEntId(this.entity.getId());
 			
--- a/src/main/java/de/mpiwg/itgroup/ismi/entry/beans/CurrentTextBean.java	Thu Feb 23 19:25:37 2017 +0100
+++ b/src/main/java/de/mpiwg/itgroup/ismi/entry/beans/CurrentTextBean.java	Fri Feb 24 20:25:33 2017 +0100
@@ -555,30 +555,29 @@
 			/*
 			 * set relations
 			 */
-			this.entity.replaceSourceRelation(commentaryLo.entity, TEXT, "is_commentary_on");
+			this.entity.replaceUniqueSourceRelation(commentaryLo.entity, TEXT, "is_commentary_on");
 			
-			this.entity.replaceSourceRelation(translationLo.entity, TEXT, "is_translation_of");
+			this.entity.replaceUniqueSourceRelation(translationLo.entity, TEXT, "is_translation_of");
 			
-			this.entity.replaceSourceRelation(versionLo.entity, TEXT, "is_version_of");
+			this.entity.replaceUniqueSourceRelation(versionLo.entity, TEXT, "is_version_of");
 			
-			this.entity.replaceSourceRelation(authorLo.entity, PERSON, "was_created_by");
-			
-			this.entity.replaceSourceRelation(dedicatedPersonLo.entity, PERSON, "was_dedicated_to");
+			this.entity.replaceUniqueSourceRelation(authorLo.entity, PERSON, "was_created_by");
 			
-			replaceAliasSourceRelation(this.entity, this.placeLo, PLACE, "was_created_in", "was_created_in_as"); 
+			this.entity.replaceUniqueSourceRelation(dedicatedPersonLo.entity, PERSON, "was_dedicated_to");
 			
-			this.entity.removeAllSourceRelations(has_subject, SUBJECT);
+			replaceUniqueAliasSourceRelation(this.entity, this.placeLo, PLACE, "was_created_in", "was_created_in_as"); 
+			
 			if (getIdSubject() != null) {
 				this.subject = getWrapper().getEntityByIdWithContent(getIdSubject());
-				this.entity.replaceSourceRelation(subject, SUBJECT, has_subject);
+				this.entity.replaceUniqueSourceRelation(subject, SUBJECT, has_subject);
+			} else {
+				this.entity.removeAllSourceRelations(has_subject, SUBJECT);
 			}
 			
 			/*
 			 * set short title (is_prime_alias_title_of)
 			 */
 			if (!StringUtils.isEmpty(valueShortTitle)) {
-				this.entity.removeAllTargetRelations("is_prime_alias_title_of", ALIAS);
-			
 				if (this.shortTitleAlias == null) {
 					//1)create  alias, 2) update value of alias3) save alias, and 4) add to this text.
 					shortTitleAlias = new Entity(Node.TYPE_ABOX, ALIAS, false);
@@ -590,35 +589,24 @@
 					this.shortTitleAlias.removeAllSourceRelations("is_prime_alias_title_of", TEXT);
 					getWrapper().saveEntity(shortTitleAlias, getUserName(), null);
 				}
-				new Relation(shortTitleAlias, this.entity, "is_prime_alias_title_of");
+				
+				this.entity.replaceUniqueTargetRelation(shortTitleAlias, ALIAS, is_prime_alias_title_of);
 			}
 			
 			/*
 			 * set alias title (ALIAS -> is_alias_title_of -> TEXT)
 			 */
-			this.entity.removeAllTargetRelationsByName("is_alias_title_of");
-			for(Entity alias : this.aliasList.getEntities()){
-				Entity alias0 = getWrapper().getEntityByIdWithContent(alias.getId());
-				new Relation(alias0, this.entity, "is_alias_title_of");
-			}
+			replaceMultipleTargetRelations(entity, aliasList.getEntities(), ALIAS, is_alias_title_of);
 			
 			/*
 			 * set alias incipit
 			 */
-			this.entity.removeAllTargetRelationsByName("is_alias_incipit_of");
-			for(Entity alias : this.incipitAliasList.getEntities()){
-				Entity alias0 = getWrapper().getEntityByIdWithContent(alias.getId());
-				new Relation(alias0, this.entity, "is_alias_incipit_of");
-			}
+			replaceMultipleTargetRelations(entity, incipitAliasList.getEntities(), ALIAS, "is_alias_incipit_of");
 			
 			/*
 			 * save alias explicit
 			 */
-			this.entity.removeAllTargetRelationsByName("is_alias_explicit_of");
-			for(Entity alias : this.explicitAliasList.getEntities()){
-				Entity alias0 = getWrapper().getEntityByIdWithContent(alias.getId());
-				new Relation(alias0, this.entity, "is_alias_explicit_of");
-			}
+			replaceMultipleTargetRelations(entity, explicitAliasList.getEntities(), ALIAS, "is_alias_explicit_of");
 			
 			// set references
 			this.prepareEndNoteRefs2Save();
--- a/src/main/java/de/mpiwg/itgroup/ismi/entry/beans/CurrentWitnessBean.java	Thu Feb 23 19:25:37 2017 +0100
+++ b/src/main/java/de/mpiwg/itgroup/ismi/entry/beans/CurrentWitnessBean.java	Fri Feb 24 20:25:33 2017 +0100
@@ -224,30 +224,25 @@
 			this.entity = this.updateEntityAttributes(this.entity);
 
 			// WITNESS -> is_part_of -> CODEX
-			this.entity.replaceSourceRelation(getCodexLo().entity, CODEX, is_part_of);
+			this.entity.replaceUniqueSourceRelation(getCodexLo().entity, CODEX, is_part_of);
 			
 			// WITNESS -> is_exemplar_of -> TEXT -> was_created_by -> PERSON
 			//replaceSourceRelation(this.entity, this.author, PERSON, was_created_by);
 
 			// WITENSS -> was_copied_by -> PERSON
-			this.entity.replaceSourceRelation(this.copyistLo.entity, PERSON, rel_was_copied_by);
+			this.entity.replaceUniqueSourceRelation(this.copyistLo.entity, PERSON, rel_was_copied_by);
 			
 			// WITNESS -> was_copied_in -> PLACE
-			replaceAliasSourceRelation(this.entity, this.copyPlaceLo, PLACE, "was_copied_in", "was_copied_in_as");
+			replaceUniqueAliasSourceRelation(this.entity, this.copyPlaceLo, PLACE, rel_was_copied_in, rel_was_copied_in_as);
 			
 			//REFERENCE -> is_reference_of -> WITNESS
-			//this.entity = this.prepareReferencesToSave(this.entity);
 			this.prepareEndNoteRefs2Save();
 			
 			//WITNESS -> was studied by manyToMany -> PERSON
-			this.entity.removeAllSourceRelationsByName(rel_was_studied_by);
-			for(Entity target : this.studiedByList.getEntities()){
-				Entity target0 = getWrapper().getEntityByIdWithContent(target.getId());
-				new Relation(this.entity, target0, rel_was_studied_by);
-			}
+			replaceMultipleSourceRelations(entity, studiedByList.getEntities(), PERSON, rel_was_studied_by);
 
 			// WITNESS -> had_patron -> PERSON
-			this.entity.replaceSourceRelation(this.patronageLo.entity, PERSON, rel_had_patron);
+			this.entity.replaceUniqueSourceRelation(this.patronageLo.entity, PERSON, rel_had_patron);
 			
 			
 			/*
@@ -256,27 +251,21 @@
 			this.entity = this.misidentTable.saveMisidentifications(this.entity);
 			
 			// WITNESS -> is_exemplar_of -> TEXT
-			this.entity.replaceSourceRelation(this.titleLo.entity, TEXT, is_exemplar_of);
+			this.entity.replaceUniqueSourceRelation(this.titleLo.entity, TEXT, is_exemplar_of);
+			
 			// legacy relations(?)
 			this.entity.removeAllSourceRelationsByName(is_possible_exemplar_of);
 			this.entity.removeAllSourceRelations(rel_has_title_written_as, ALIAS);
 			this.entity.removeAllSourceRelations(rel_has_author_written_as, ALIAS);
 			
-			if(textUnknown){
-				for(Entity target : this.possibleExamplerOfList.getEntities()){
-					Entity target0 = getWrapper().getEntityByIdWithContent(target.getId());
-					new Relation(this.entity, target0, is_possible_exemplar_of);
-				}
-			}else{
-				this.saveIndirectedAliases();
-			}
-			
 			// WITNESS -> is_part_of_codex 
 			if(this.isSelectedSaveAsNew()){
 				//this.entity = getWrapper().saveEntityAsNew(this.entity, user.getEmail());
 			}else{
+				// save this entity
 				this.entity = getWrapper().saveEntity(this.entity, user.getEmail(), editWitnessIntent);
 			}
+			// re-set form
 			this.setEntity(this.entity);
 			
 			logger.info("Entity saved - Time = " + (System.currentTimeMillis() - start) + ", " + entity);
@@ -292,89 +281,11 @@
 		return PAGE_EDITOR;
 	}
 
-	private void saveIndirectedAliases() throws Exception{
-		
-		User user = getSessionUser();
-		
-		//WITNESS -> has_title_written_as -> ALIAS
-		if(StringUtils.isNotEmpty(valueTextWritten)){
-			Entity alias = null;
-			if(this.suggestedTitlesWritten != null){
-				for(SelectItem item : this.suggestedTitlesWritten){
-					Long id = (Long)item.getValue();
-					if(id != null){
-						Entity candidate = getWrapper().getEntityById(id);
-						if(candidate != null && valueTextWritten.equals(candidate.getOwnValue())){
-							alias = candidate;
-							break;
-						}
-					}
-				}
-			}
-			
-			if(alias == null){
-				alias = new Entity(Node.TYPE_ABOX, ALIAS, false);
-				alias.addAttribute(new Attribute(ALIAS, "text", valueTextWritten));
-				alias = getWrapper().saveEntity(alias, user.getEmail(), null);
-				new Relation(alias, this.titleLo.getEntity(), "is_alias_title_of");
-				alias = getWrapper().saveEntity(alias, user.getEmail(), null);
-			}			
-			if(alias.isLightweight()){
-				alias = getWrapper().getEntityByIdWithContent(alias.getId());
-			}
-			this.entity.replaceSourceRelation(alias, ALIAS, rel_has_title_written_as);
-		}
-				
-		
-		if(StringUtils.isNotEmpty(this.valueAuthorWritten)){
-			Entity alias = null;
-			if(suggestedAuthorsWritten != null){
-				for(SelectItem item : this.suggestedAuthorsWritten){
-					Long id = (Long)item.getValue();
-					if(id != null){
-						Entity candidate = getWrapper().getEntityById(id);
-						if(candidate != null && valueAuthorWritten.equals(candidate.getOwnValue())){
-							alias = candidate;
-							break;
-						}
-					}
-				}
-			}
-			
-			if(alias == null){
-				alias = new Entity(Node.TYPE_ABOX, ALIAS, false);
-				alias.addAttribute(new Attribute(ALIAS, "text", valueAuthorWritten));
-				alias = getWrapper().saveEntity(alias, user.getEmail(), null);
-				new Relation(alias, this.authorLo.getEntity(), "is_alias_name_of");
-				alias = getWrapper().saveEntity(alias, user.getEmail(), null);
-			}
-			if(alias.isLightweight()){
-				alias = getWrapper().getEntityByIdWithContent(alias.getId());
-			}
-			this.entity.replaceSourceRelation(alias, ALIAS, rel_has_author_written_as);
-		}
-	}
-	
 	public String saveAsNewEntity() {
 		this.setSelectedSaveAsNew(true);
 		return save();
 	}
 
-	/* rich
-	public void patronageChangeListener(ValueChangeEvent event) {
-		//patronageLo = changeListener(event, patronageLo, PERSON, "name");
-		patronageLo = changeValuePersonByRole(event, patronageLo, "Patron");
-	
-	}
-	
-	public void copyistChangeListener(ValueChangeEvent event) {
-		copyistLo = changeValuePersonByRole(event, copyistLo, "Copyist");	
-	}
-
-	public void copyPlacesChangeListener(ValueChangeEvent event) {
-		copyPlaceLo = changeListener(event, copyPlaceLo,"PLACE", "name");
-	}*/
-	
 	public void updateTitle(){
 		
 		if(titleLo.entity != null && titleLo.entity.isPersistent()){
--- a/src/main/java/de/mpiwg/itgroup/ismi/event/beans/CopyEvent.java	Thu Feb 23 19:25:37 2017 +0100
+++ b/src/main/java/de/mpiwg/itgroup/ismi/event/beans/CopyEvent.java	Fri Feb 24 20:25:33 2017 +0100
@@ -124,19 +124,19 @@
 			event = updateEntityAttributes(event);
 			
 			// EVENT -> was_copied_for -> PERSON
-			event.replaceSourceRelation(personCopiedForLo.entity, PERSON, was_copied_for);
+			event.replaceUniqueSourceRelation(personCopiedForLo.entity, PERSON, was_copied_for);
 
 			// EVENT -> has_person_copying_text -> PERSON
-			event.replaceSourceRelation(personCopyingTextLo.entity, PERSON, has_person_copying_text);
+			event.replaceUniqueSourceRelation(personCopyingTextLo.entity, PERSON, has_person_copying_text);
 						
 			// EVENT -> was_copied_in -> PLACE
-			replaceAliasSourceRelation(event, placeLo, PLACE, was_copied_in, was_copied_in_as);
+			replaceUniqueAliasSourceRelation(event, placeLo, PLACE, was_copied_in, was_copied_in_as);
 
 			// EVENT -> is_a_copy_of -> WITNESS
             if (witness.isLightweight()) {
                 this.witness = getWrapper().getEntityByIdWithContent(witness.getId());
             }
-			event.replaceSourceRelation(witness, WITNESS, is_a_copy_of);
+			event.replaceUniqueSourceRelation(witness, WITNESS, is_a_copy_of);
 			
 			getWrapper().saveEntity(event, getSessionUserName(), null);
 			
--- a/src/main/java/de/mpiwg/itgroup/ismi/event/beans/StudyEvent.java	Thu Feb 23 19:25:37 2017 +0100
+++ b/src/main/java/de/mpiwg/itgroup/ismi/event/beans/StudyEvent.java	Fri Feb 24 20:25:33 2017 +0100
@@ -115,19 +115,19 @@
 			event = updateEntityAttributes(event);
 			
 			// EVENT -> was_studied_by -> PERSON
-			event.replaceSourceRelation(personLo.entity, PERSON, was_studied_by);
+			event.replaceUniqueSourceRelation(personLo.entity, PERSON, was_studied_by);
 
 			// EVENT -> was_advised_by -> PERSON
-			event.replaceSourceRelation(advisorLo.entity, PERSON, was_advised_by);
+			event.replaceUniqueSourceRelation(advisorLo.entity, PERSON, was_advised_by);
 						
 			// EVENT -> was_studied_in -> PLACE
-			replaceAliasSourceRelation(event, placeLo, PLACE, was_studied_in, was_studied_in_as);
+			replaceUniqueAliasSourceRelation(event, placeLo, PLACE, was_studied_in, was_studied_in_as);
 
 			// EVENT -> is_a_study_of -> WITNESS
 			if(witness.isLightweight()){
 				witness = getWrapper().getEntityByIdWithContent(witness.getId());
 			}
-			event.replaceSourceRelation(witness, WITNESS, is_a_study_of);
+			event.replaceUniqueSourceRelation(witness, WITNESS, is_a_study_of);
 			
 			getWrapper().saveEntity(event, getSessionUserName(), null);
 			
--- a/src/main/java/de/mpiwg/itgroup/ismi/event/beans/TransferEvent.java	Thu Feb 23 19:25:37 2017 +0100
+++ b/src/main/java/de/mpiwg/itgroup/ismi/event/beans/TransferEvent.java	Fri Feb 24 20:25:33 2017 +0100
@@ -166,22 +166,22 @@
 			if (witness.isLightweight()) {
 				this.witness = getWrapper().getEntityByIdWithContent(witness.getId());
 			}
-			event.replaceSourceRelation(witness, WITNESS, is_a_transfer_of);
+			event.replaceUniqueSourceRelation(witness, WITNESS, is_a_transfer_of);
 			
 			// EVENT -> was_transferred_from -> PERSON
-			event.replaceSourceRelation(personFromLo.entity, PERSON, was_transferred_from);
+			event.replaceUniqueSourceRelation(personFromLo.entity, PERSON, was_transferred_from);
 
 			// EVENT -> was_transferred_to -> PERSON
-			event.replaceSourceRelation(personToLo.entity, PERSON, was_transferred_to);
+			event.replaceUniqueSourceRelation(personToLo.entity, PERSON, was_transferred_to);
 			
 			// EVENT -> has_original_location -> PLACE
-			event.replaceSourceRelation(placeOriginalLocationLo.entity, PLACE, has_original_location);
+			event.replaceUniqueSourceRelation(placeOriginalLocationLo.entity, PLACE, has_original_location);
 			
 			// EVENT -> has_new_location -> PLACE
-			event.replaceSourceRelation(placeNewLocationLo.entity, PLACE, has_new_location);
+			event.replaceUniqueSourceRelation(placeNewLocationLo.entity, PLACE, has_new_location);
 			
 			// EVENT -> was_transferred_in -> PLACE
-			event.replaceSourceRelation(placeLo.entity, PLACE, was_transferred_in);
+			event.replaceUniqueSourceRelation(placeLo.entity, PLACE, was_transferred_in);
 			
 			getWrapper().saveEntity(event, getSessionUserName(), null);
 			
--- a/src/main/java/de/mpiwg/itgroup/ismi/merge/ImportMerge.java	Thu Feb 23 19:25:37 2017 +0100
+++ b/src/main/java/de/mpiwg/itgroup/ismi/merge/ImportMerge.java	Fri Feb 24 20:25:33 2017 +0100
@@ -219,12 +219,15 @@
                 Long source_id = rel.getSourceId();
                 Long target_id = rel.getTargetId();
                 if (source_id == null) {
+                	// no source id
                     importNodeMsg = "Relation has no source_id!";
                     return;
                 } else if (target_id == null) {
+                	// no target id
                     importNodeMsg = "Relation has no target_id!";
                     return;
                 } else {
+                	// get source and target Entities
                     Entity sourceEnt = getWrapper().getEntityById(source_id);
                     Entity targetEnt = getWrapper().getEntityById(target_id);
                     if (sourceEnt == null) {
@@ -235,6 +238,7 @@
                         if (sourceEnt.isLightweight()) {
                             sourceEnt = getWrapper().getEntityContent(sourceEnt);
                         }
+                        // get existing Relation
                         Relation systemRel = sourceEnt.getSourceRelation(relName, target_id);
                         if ((systemRel != null) && (systemRel.getObjectClass().equals(rel.getObjectClass()))) {
                             // TODO: also check Relation attributes
--- a/src/main/webapp/entry/codex.xhtml	Thu Feb 23 19:25:37 2017 +0100
+++ b/src/main/webapp/entry/codex.xhtml	Fri Feb 24 20:25:33 2017 +0100
@@ -233,7 +233,7 @@
 		<h:panelGrid columns="2" styleClass="createPanel"
 			columnClasses="createPanelFirstColumn">
 
-			<h:outputText value="Owned By (event)" />
+			<h:outputText value="Owned By" />
 
 			<h:panelGrid columns="2" id="ownedEventPanel">
 				<rich:dataTable value="#{CurrentCodex.ownedByPeople.entities}"
@@ -275,7 +275,7 @@
 			</h:panelGrid>
 
 
-			<h:outputText value="Read by (event)" />
+			<h:outputText value="Read by" />
 			<h:panelGrid columns="2" id="readByEventPanel">
 
 				<rich:dataTable value="#{CurrentCodex.readByPeople.entities}"