in grails-data-neo4j/grails-datastore-gorm-neo4j/src/main/groovy/org/grails/datastore/gorm/neo4j/engine/Neo4jEntityPersister.java [105:257]
protected List<Serializable> persistEntities(final PersistentEntity pe, @SuppressWarnings("rawtypes") final Iterable objs) {
GraphPersistentEntity graphPersistentEntity = (GraphPersistentEntity) pe;
List<Serializable> idList = new ArrayList<>();
if(graphPersistentEntity.hasDynamicAssociations()) {
// dynamic association entities cannot be batch inserted
for (Object obj : objs) {
Serializable id = persistEntity(pe, obj);
if(id != null) {
idList.add(id);
}
}
}
else if(graphPersistentEntity.isNativeId() && !graphPersistentEntity.isRelationshipEntity()) {
List<EntityAccess> entityAccesses = new ArrayList<>();
// optimize batch inserts for multiple entities with native id
final Neo4jSession session = getSession();
StringBuilder createCypher = new StringBuilder(CypherBuilder.CYPHER_CREATE);
int listIndex = 0;
List<PendingOperation<Object,Serializable>> cascadingOperations = new ArrayList<>();
final Map<String, Object> params = new HashMap<>(1);
final Map<Integer, Integer> indexMap = new HashMap<>();
int insertIndex = 0;
final Iterator iterator = objs.iterator();
boolean previous = false;
while (iterator.hasNext()) {
Object obj = iterator.next();
listIndex++;
if (shouldIgnore(session, obj)) {
EntityAccess entityAccess = createEntityAccess(pe, obj);
idList.add((Serializable) entityAccess.getIdentifier());
continue;
}
final EntityAccess entityAccess = createEntityAccess(pe, obj);
GraphPersistentEntity persistentEntity = (GraphPersistentEntity) entityAccess.getPersistentEntity();
if (getMappingContext().getProxyFactory().isProxy(obj)) {
idList.add(((EntityProxy) obj).getProxyKey());
continue;
}
session.registerPending(obj);
Serializable identifier = (Serializable) entityAccess.getIdentifier();
boolean isUpdate = identifier != null;
if (isUpdate) {
registerPendingUpdate(session, persistentEntity, entityAccess, obj, identifier);
idList.add(identifier);
}
else {
final PendingInsertAdapter<Object, Serializable> pendingInsert = new PendingInsertAdapter<Object, Serializable>(persistentEntity, identifier, obj, entityAccess) {
@Override
public void run() {
if (cancelInsert(pe, entityAccess)) {
setVetoed(true);
}
}
@Override
public Serializable getNativeKey() {
return (Serializable) entityAccess.getIdentifier();
}
};
pendingInsert.addCascadeOperation(new PendingOperationAdapter<Object, Serializable>(persistentEntity, identifier, obj) {
@Override
public void run() {
firePostInsertEvent(pe, entityAccess);
}
});
cascadingOperations.addAll(pendingInsert.getCascadeOperations());
final List<PendingOperation<Object, Serializable>> preOperations = pendingInsert.getPreOperations();
for (PendingOperation preOperation : preOperations) {
preOperation.run();
}
pendingInsert.run();
pendingInsert.setExecuted(true);
// temporarily add null so it is replaced later
idList.add(null);
if(pendingInsert.isVetoed()) {
continue;
}
session.addPendingInsert(pendingInsert);
indexMap.put(insertIndex++, listIndex - 1);
entityAccesses.add(entityAccess);
if(previous) {
createCypher.append(CypherBuilder.COMMAND_SEPARATOR);
}
session.buildEntityCreateOperation(createCypher, String.valueOf(insertIndex), entityAccess.getPersistentEntity(), pendingInsert, params, cascadingOperations);
if(iterator.hasNext()) {
previous = true;
}
}
}
if(insertIndex > 0) {
QueryRunner statementRunner = session.hasTransaction() ? session.getTransaction().getNativeTransaction() : session.getNativeInterface();
final String finalCypher = createCypher.toString() + " RETURN *";
if(log.isDebugEnabled()) {
log.debug("CREATE Cypher [{}] for parameters [{}]", finalCypher, params);
}
if(graphPersistentEntity.hasDynamicAssociations()) {
params.remove(DYNAMIC_ASSOCIATION_PARAM);
}
final Result result = statementRunner.run(finalCypher, params);
if(!result.hasNext()) {
throw new IdentityGenerationException("CREATE operation did not generate an identifier for entity " + pe.getJavaClass());
}
final Record record = result.next();
for (int j = 0; j < insertIndex; j++) {
final Integer targetIndex = indexMap.get(j);
Assert.notNull(targetIndex, "Should never be null. Please file an issue");
final Node node = record.get("n" + (j + 1)).asNode();
if(node == null) {
throw new IdentityGenerationException("CREATE operation did not generate an identifier for entity " + pe.getJavaClass());
}
final long identifier = node.id();
final EntityAccess entityAccess = entityAccesses.get(j);
entityAccess.setIdentifier(identifier);
idList.set(targetIndex, identifier);
persistAssociationsOfEntity((GraphPersistentEntity) pe, entityAccess, false);
}
}
}
else {
for (Object obj : objs) {
final EntityAccess entityAccess = createEntityAccess(pe, obj);
Serializable id = persistEntity(entityAccess.getPersistentEntity(), obj);
if(id != null) {
idList.add(id);
}
}
}
return idList;
}