Example #1
0
        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;
        }
Example #2
0
        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...
            }
        }