public static List <BasePenguin> UpdatePenguin(ITransaction transaction, List <BasePenguin> penguinsToUpdate) { var newRelations = new Dictionary <string, List <object> >(); var removeRelations = new Dictionary <string, List <object> >(); if (penguinsToUpdate.Any(i => !i.ID.HasValue)) { throw new InvalidOperationException("Penguin to update must have an ID."); } foreach (var penguin in penguinsToUpdate) { penguin.DirtyDatastore.Relations.UnionAllValues().Except(penguin.Datastore.Relations.UnionAllValues()).ForEach(i => { newRelations.CreateOrAddToList(i.RelationName, ConvertToNeo4jRelationObj(penguin.ID.Value, i)); }); penguin.Datastore.Relations.UnionAllValues().Except(penguin.DirtyDatastore.Relations.UnionAllValues()).ForEach(i => { removeRelations.CreateOrAddToList(i.RelationName, ConvertToNeo4jRelationObj(penguin.ID.Value, i)); }); } foreach (var kvp in removeRelations) { transaction.Run($"UNWIND $relations as relation MATCH (a)-[r:{kvp.Key}]->(b) WHERE id(a) = relation.from AND id(b) = relation.to DELETE r", new { relations = kvp.Value }); } transaction.Run("UNWIND $relations as relation MATCH (a),(b) WHERE id(a)=relation.from AND id(b) = relation.to CALL apoc.create.relationship(a, relation.name, relation.param, b) YIELD rel RETURN rel", new { relations = newRelations.UnionAllValues() }); var result = penguinsToUpdate.ConvertAll(i => new BasePenguin(i.ID.Value, Datastore.Combine(i.Datastore, i.DirtyDatastore))); var props = result.Select(i => new { id = i.ID.Value, attributes = i.Datastore.Attributes }); transaction.Run("UNWIND $props as prop MATCH (obj) WHERE id(obj) = prop.id SET obj = prop.attributes RETURN obj", new { props }); return(result); }