/** * Add a collection of objects of type X to objects of type Y by using a connecting class. Eg. Add * a collection of Protein objects to Gene by examining the Transcript objects in the transcripts * collection of the Gene, which would use a query like: SELECT DISTINCT gene FROM Gene AS gene, * Transcript AS transcript, Protein AS protein WHERE (gene.transcripts CONTAINS transcript AND * transcript.protein CONTAINS protein) ORDER BY gene and then set protected gene.protein (if * created BioEntity1 -> BioEntity2 -> BioEntity3 ==> BioEntity1 -> BioEntity3 * * @param firstClsName the first class in the query * @param firstClassFieldName the field in the firstClass which should contain the connectingClass * @param connectingClsName the class referred to by firstClass.sourceFieldName * @param connectingClassFieldName the field in connectingClass which should contain secondClass * @param secondClsName the class referred to by connectingClass.connectingClassFieldName * @param createFieldName the collection field in the secondClass - the collection to create/set * @param createInFirstClass if true create the new collection field in firstClass, otherwise * create in secondClass * @throws Exception if anything goes wrong */ protected void insertCollectionField( String firstClsName, String firstClassFieldName, String connectingClsName, String connectingClassFieldName, String secondClsName, String createFieldName, boolean createInFirstClass) throws Exception { InterMineObject lastDestObject = null; Set<InterMineObject> newCollection = new HashSet<InterMineObject>(); String insertMessage = "insertCollectionField(" + firstClsName + ", " + firstClassFieldName + ", " + connectingClsName + ", " + connectingClassFieldName + "," + secondClsName + ", " + createFieldName + ", " + createInFirstClass + ")"; // Check that classes and fields specified exist in model try { String errorMessage = "Not performing " + insertMessage; PostProcessUtil.checkFieldExists(model, firstClsName, firstClassFieldName, errorMessage); PostProcessUtil.checkFieldExists( model, connectingClsName, connectingClassFieldName, errorMessage); PostProcessUtil.checkFieldExists(model, secondClsName, createFieldName, errorMessage); } catch (MetaDataException e) { return; } LOG.info("Beginning " + insertMessage); long startTime = System.currentTimeMillis(); // if this is a many to many collection we can use ObjectStore.addToCollection which will // write directly to the database. boolean manyToMany = false; ClassDescriptor destCld; if (createInFirstClass) { destCld = model.getClassDescriptorByName(firstClsName); } else { destCld = model.getClassDescriptorByName(secondClsName); } CollectionDescriptor col = destCld.getCollectionDescriptorByName(createFieldName); if (col == null) { String msg = "Error running post-process `create-references` for `" + createFieldName + "` since this collection doesn't exist in the model."; LOG.error(msg); return; } if (col.relationType() == CollectionDescriptor.M_N_RELATION) { manyToMany = true; } Iterator<ResultsRow<InterMineObject>> resIter = PostProcessUtil.findConnectingClasses( osw.getObjectStore(), model.getClassDescriptorByName(firstClsName).getType(), firstClassFieldName, model.getClassDescriptorByName(connectingClsName).getType(), connectingClassFieldName, model.getClassDescriptorByName(secondClsName).getType(), createInFirstClass); // results will be firstClass ; destClass (ordered by firstClass) osw.beginTransaction(); int count = 0; while (resIter.hasNext()) { ResultsRow<InterMineObject> rr = resIter.next(); InterMineObject thisSourceObject; InterMineObject thisDestObject; if (createInFirstClass) { thisDestObject = rr.get(0); thisSourceObject = rr.get(1); } else { thisDestObject = rr.get(1); thisSourceObject = rr.get(0); } if (!manyToMany && (lastDestObject == null || !thisDestObject.getId().equals(lastDestObject.getId()))) { if (lastDestObject != null) { try { InterMineObject tempObject = PostProcessUtil.cloneInterMineObject(lastDestObject); Set<InterMineObject> oldCollection = (Set<InterMineObject>) tempObject.getFieldValue(createFieldName); newCollection.addAll(oldCollection); tempObject.setFieldValue(createFieldName, newCollection); count += newCollection.size(); osw.store(tempObject); } catch (IllegalAccessException e) { LOG.error( "Object with ID " + thisDestObject.getId() + " has no " + createFieldName + " field", e); } } newCollection = new HashSet<InterMineObject>(); } if (manyToMany) { osw.addToCollection( thisDestObject.getId(), destCld.getType(), createFieldName, thisSourceObject.getId()); } else { newCollection.add(thisSourceObject); } lastDestObject = thisDestObject; } if (!manyToMany && lastDestObject != null) { // clone so we don't change the ObjectStore cache InterMineObject tempObject = PostProcessUtil.cloneInterMineObject(lastDestObject); tempObject.setFieldValue(createFieldName, newCollection); count += newCollection.size(); osw.store(tempObject); } LOG.info( "Finished: created " + count + " references in " + secondClsName + " to " + firstClsName + " via " + connectingClsName + " - took " + (System.currentTimeMillis() - startTime) + " ms."); osw.commitTransaction(); // now ANALYSE tables relation to class that has been altered - may be rows added // to indirection tables if (osw instanceof ObjectStoreWriterInterMineImpl) { ClassDescriptor cld = model.getClassDescriptorByName(secondClsName); DatabaseUtil.analyse(((ObjectStoreWriterInterMineImpl) osw).getDatabase(), cld, false); } }