public override void Delete(OGM item) { Transaction trans = Transaction.RunningTransaction; Entity entity = item.GetEntity(); string match; Dictionary <string, object?> parameters = new Dictionary <string, object?>(); parameters.Add("key", item.GetKey()); if (entity.RowVersion == null) { match = string.Format("MATCH (node:{0}) WHERE node.{1} = {{key}} DELETE node", entity.Label.Name, entity.Key.Name); } else { parameters.Add("lockId", Conversion <DateTime, long> .Convert(item.GetRowVersion())); match = string.Format("MATCH (node:{0}) WHERE node.{1} = {{key}} AND node.{2} = {{lockId}} DELETE node", entity.Label.Name, entity.Key.Name, entity.RowVersion.Name); } Dictionary <string, object?>?customState = null; var args = entity.RaiseOnNodeDelete(trans, item, match, parameters, ref customState); RawResult result = trans.Run(args.Cypher, args.Parameters); if (result.Statistics().NodesDeleted == 0) { throw new DBConcurrencyException($"The {entity.Name} with {entity.Key.Name} '{item.GetKey()?.ToString() ?? "<NULL>"}' was changed or deleted by another process or thread."); } entity.RaiseOnNodeDeleted(trans, args); item.PersistenceState = PersistenceState.Deleted; }
internal static void ExecuteBatched(string cypher, Dictionary <string, object> parameters) { if (!ShouldExecute) { return; } RawResultStatistics counters; do { using (Transaction.Begin(true)) { RawResult result = Parser.PrivateExecute(cypher, parameters); Transaction.Commit(); counters = result.Statistics(); } }while (counters.ContainsUpdates); }
public override void Remove(Relationship relationship, OGM inItem, OGM outItem, DateTime?moment, bool timedependent) { Transaction trans = Transaction.RunningTransaction; Checks(relationship, inItem, outItem); string cypher; Dictionary <string, object?> parameters = new Dictionary <string, object?>(); parameters.Add("inKey", inItem.GetKey()); parameters.Add("outKey", outItem.GetKey()); if (timedependent) { parameters.Add("moment", Conversion <DateTime, long> .Convert(moment ?? DateTime.MinValue)); // End Current cypher = string.Format( "MATCH (in:{0})-[r:{1}]->(out:{2}) WHERE in.{3} = {{inKey}} and out.{4} = {{outKey}} and (r.{6} > {{moment}} OR r.{6} IS NULL) AND (r.{5} <={{moment}} OR r.{5} IS NULL) SET r.EndDate = {{moment}}", inItem.GetEntity().Label.Name, relationship.Neo4JRelationshipType, outItem.GetEntity().Label.Name, inItem.GetEntity().Key.Name, outItem.GetEntity().Key.Name, relationship.StartDate, relationship.EndDate); trans.Run(cypher, parameters); // Remove Future cypher = string.Format( "MATCH (in:{0})-[r:{1}]->(out:{2}) WHERE in.{3} = {{inKey}} and out.{4} = {{outKey}} and r.{5} > {{moment}} DELETE r", inItem.GetEntity().Label.Name, relationship.Neo4JRelationshipType, outItem.GetEntity().Label.Name, inItem.GetEntity().Key.Name, outItem.GetEntity().Key.Name, relationship.StartDate); relationship.RaiseOnRelationDelete(trans); RawResult result = trans.Run(cypher, parameters); relationship.RaiseOnRelationDeleted(trans); if (result.Statistics().RelationshipsDeleted == 0) { throw new ApplicationException($"Unable to delete time dependent future relationship '{relationship.Neo4JRelationshipType}' between {inItem.GetEntity().Label.Name}({inItem.GetKey()}) and {outItem.GetEntity().Label.Name}({outItem.GetKey()})"); } } else { cypher = string.Format( "MATCH (in:{0})-[r:{1}]->(out:{2}) WHERE in.{3} = {{inKey}} and out.{4} = {{outKey}} DELETE r", inItem.GetEntity().Label.Name, relationship.Neo4JRelationshipType, outItem.GetEntity().Label.Name, inItem.GetEntity().Key.Name, outItem.GetEntity().Key.Name); relationship.RaiseOnRelationDelete(trans); RawResult result = trans.Run(cypher, parameters); relationship.RaiseOnRelationDeleted(trans); if (result.Statistics().RelationshipsDeleted == 0) { throw new ApplicationException($"Unable to delete relationship '{relationship.Neo4JRelationshipType}' between {inItem.GetEntity().Label.Name}({inItem.GetKey()}) and {outItem.GetEntity().Label.Name}({outItem.GetKey()})"); } } }
protected virtual void Add(Transaction trans, Relationship relationship, OGM inItem, OGM outItem, DateTime moment) { // Expected behavior time dependent relationship: // ---------------------------------------------- // // Match existing relation where in & out item // IsAfter -> Remove relation // OverlapsOrIsAttached -> Set relation.EndDate to Conversion.MaxEndDate // // if (result.Statistics().PropertiesSet == 0) <--- this needs to be executed in the same statement // Add relation Entity inEntity = inItem.GetEntity(); Entity outEntity = outItem.GetEntity(); StringBuilder sb = new StringBuilder(); sb.AppendLine($"MATCH (in:{inEntity.Label.Name} {{ {inEntity.Key.Name}: $inKey }})-[rel:{relationship.Neo4JRelationshipType}]->(out:{outEntity.Label.Name} {{ {outEntity.Key.Name}: $outKey }})"); sb.AppendLine("WHERE COALESCE(rel.StartDate, $min) >= $moment"); sb.AppendLine("DELETE rel"); string delete = sb.ToString(); sb.Clear(); sb.AppendLine($"MATCH (in:{inEntity.Label.Name} {{ {inEntity.Key.Name}: $inKey }})-[rel:{relationship.Neo4JRelationshipType}]->(out:{outEntity.Label.Name} {{ {outEntity.Key.Name}: $outKey }})"); sb.AppendLine("WHERE COALESCE(rel.StartDate, $min) <= $moment AND COALESCE(rel.EndDate, $max) >= $moment"); sb.AppendLine("SET rel.EndDate = $max"); string update = sb.ToString(); sb.Clear(); sb.AppendLine($"MATCH (in:{inEntity.Label.Name} {{ {inEntity.Key.Name}: $inKey }}), (out:{outEntity.Label.Name} {{ {outEntity.Key.Name}: $outKey }})"); sb.AppendLine($"OPTIONAL MATCH (in)-[rel:{relationship.Neo4JRelationshipType}]->(out)"); sb.AppendLine("WHERE COALESCE(rel.StartDate, $min) <= $moment AND COALESCE(rel.EndDate, $max) >= $moment"); sb.AppendLine("WITH in, out, rel"); sb.AppendLine("WHERE rel is null"); sb.AppendLine($"CREATE (in)-[outr:{relationship.Neo4JRelationshipType}]->(out) SET outr.CreationDate = $create SET outr += $node"); string create = sb.ToString(); Dictionary <string, object> node = new Dictionary <string, object>(); node.Add(relationship.StartDate, Conversion <DateTime, long> .Convert(moment)); node.Add(relationship.EndDate, Conversion.MaxDateTimeInMS); Dictionary <string, object?> parameters = new Dictionary <string, object?>(); parameters.Add("inKey", inItem.GetKey()); parameters.Add("outKey", outItem.GetKey()); parameters.Add("create", Conversion <DateTime, long> .Convert(Transaction.RunningTransaction.TransactionDate)); parameters.Add("min", Conversion.MinDateTimeInMS); parameters.Add("max", Conversion.MaxDateTimeInMS); parameters.Add("moment", Conversion <DateTime, long> .Convert(moment)); parameters.Add("node", node); relationship.RaiseOnRelationCreate(trans); RawResult deleteResult = trans.Run(delete, parameters); RawResult updateResult = trans.Run(update, parameters); RawResult createResult = trans.Run(create, parameters); if (updateResult.Statistics().PropertiesSet > 0 && createResult.Statistics().RelationshipsCreated > 0) { throw new InvalidOperationException(); // TODO: Make the error better... } }