public override void RemoveUnmanaged(Relationship relationship, OGM inItem, OGM outItem, DateTime?moment)
        {
            Transaction trans = Transaction.RunningTransaction;

            Checks(relationship, inItem, outItem);

            if (relationship.IsTimeDependent == false)
            {
                throw new NotSupportedException("EndCurrentRelationship method is only supported for time dependent relationship.");
            }

            string match = string.Format(
                "MATCH (in:{0})-[r:{1}]->(out:{2}) WHERE in.{3} = {{inKey}} and out.{4} = {{outKey}} and COALESCE(r.{5}, {{minDateTime}}) = {{moment}} DELETE r",
                inItem.GetEntity().Label.Name,
                relationship.Neo4JRelationshipType,
                outItem.GetEntity().Label.Name,
                inItem.GetEntity().Key.Name,
                outItem.GetEntity().Key.Name,
                relationship.StartDate);

            Dictionary <string, object?> parameters = new Dictionary <string, object?>();

            parameters.Add("inKey", inItem.GetKey());
            parameters.Add("outKey", outItem.GetKey());
            parameters.Add("moment", Conversion <DateTime, long> .Convert(moment ?? DateTime.MinValue));
            parameters.Add("minDateTime", Conversion <DateTime, long> .Convert(DateTime.MinValue));

            relationship.RaiseOnRelationDelete(trans);

            trans.Run(match, parameters);

            relationship.RaiseOnRelationDeleted(trans);
        }
        protected virtual void Add(Transaction trans, Relationship relationship, OGM inItem, OGM outItem)
        {
            string match = string.Format("MATCH (in:{0}) WHERE in.{1} = $inKey \r\n MATCH (out:{2}) WHERE out.{3} = $outKey",
                                         inItem.GetEntity().Label.Name,
                                         inItem.GetEntity().Key.Name,
                                         outItem.GetEntity().Label.Name,
                                         outItem.GetEntity().Key.Name);
            string create = string.Format("MERGE (in)-[outr:{0}]->(out) ON CREATE SET outr.CreationDate = ${1} SET outr += $node", relationship.Neo4JRelationshipType, relationship.CreationDate);

            Dictionary <string, object?> parameters = new Dictionary <string, object?>();

            parameters.Add("inKey", inItem.GetKey());
            parameters.Add("outKey", outItem.GetKey());

            Dictionary <string, object> node = new Dictionary <string, object>();

            parameters.Add(relationship.CreationDate, Conversion <DateTime, long> .Convert(Transaction.RunningTransaction.TransactionDate));

            parameters.Add("node", node);

            string query = match + "\r\n" + create;

            relationship.RaiseOnRelationCreate(trans);

            RawResult result = trans.Run(query, parameters);
        }
Exemple #3
0
        static private T Activator <T>(Entity entity)
        {
            if (entity.IsAbstract)
            {
                throw new NotSupportedException($"You cannot instantiate the abstract entity {entity.Name}.");
            }

            Func <OGM> activator = activators.TryGetOrAdd(entity.Name, key =>
            {
                Dictionary <string, Func <OGM> > retval = new Dictionary <string, Func <OGM> >();

                foreach (Type type in typeof(T).Assembly.GetTypes())
                {
                    if (type.BaseType != null && type.BaseType.IsGenericType && type.BaseType.GetGenericTypeDefinition() == typeof(OGM <, ,>))
                    {
                        OGM instance          = (OGM)System.Runtime.Serialization.FormatterServices.GetUninitializedObject(type);
                        Entity entityInstance = instance.GetEntity();
                        if (entityInstance.IsAbstract)
                        {
                            continue;
                        }

                        retval.Add(entityInstance.Name, Expression.Lambda <Func <OGM> >(Expression.New(type)).Compile());
                    }
                }
                return(retval[entity.Name]);
            });

            return((T)Transaction.Execute(() => activator.Invoke(), EventOptions.GraphEvents));
        }
Exemple #4
0
        public override bool RelationshipExists(Property foreignProperty, OGM item)
        {
            string pattern;

            if (foreignProperty.Direction == DirectionEnum.In)
            {
                pattern = "MATCH (node:{0})<-[:{2}]-(:{3}) WHERE node.{1} = {{key}} RETURN node LIMIT 1";
            }
            else
            {
                pattern = "MATCH (node:{0})-[:{2}]->(:{3}) WHERE node.{1} = {{key}} RETURN node LIMIT 1";
            }

            string match = string.Format(
                pattern,
                item.GetEntity().Label.Name,
                item.GetEntity().Key.Name,
                foreignProperty.Relationship?.Neo4JRelationshipType,
                foreignProperty.Parent.Label.Name);

            Dictionary <string, object?> parameters = new Dictionary <string, object?>();

            parameters.Add("key", item.GetKey());

            var result = Transaction.RunningTransaction.Run(match, parameters);

            return(result.Any());
        }
Exemple #5
0
        internal void Register(OGM item)
        {
            if (item == null)
            {
                return;
            }

            item.Transaction = this;

            string entityName = item.GetEntity().Name;

            Dictionary <OGM, OGM>?values;

            if (!registeredEntities.TryGetValue(entityName, out values))
            {
                values = new Dictionary <OGM, OGM>(1000);
                registeredEntities.Add(entityName, values);
            }

            OGM?inSet;

            if (values.TryGetValue(item, out inSet))
            {
                if (inSet.PersistenceState != PersistenceState.DoesntExist && inSet == item)
                {
                    throw new InvalidOperationException("You cannot register an already loaded object.");
                }
            }
            else
            {
                values.Add(item, item);
            }
        }
Exemple #6
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;
        }
 public RelationshipIndex(OGM sourceEntity, OGM targetEntity, DateTime?startDate, DateTime?endDate)
 {
     SourceEntityInstance = sourceEntity;
     TargetEntityInstance = targetEntity;
     StartDate            = startDate;
     EndDate = endDate;
 }
Exemple #8
0
        internal void Register(string type, OGM item, bool noError = false)
        {
            object?key = item.GetKey();

            if (key is null)
            {
                return;
            }

            Dictionary <object, OGM>?values;

            if (!entitiesByKey.TryGetValue(type, out values))
            {
                values = new Dictionary <object, OGM>(1000);
                entitiesByKey.Add(type, values);
            }

            if (values.ContainsKey(key))
            {
                OGM similarItem = values[key];
                if (!noError && similarItem.PersistenceState != PersistenceState.HasUid && similarItem.PersistenceState != PersistenceState.DoesntExist)
                {
                    throw new InvalidOperationException("You cannot register an already loaded object.");
                }
                else
                {
                    values[key] = item;
                }
            }
            else
            {
                values.Add(key, item);
            }
        }
Exemple #9
0
	// Use this for initialization


	void Start () {
		ogm = GameObject.Find ("_OGM").GetComponent<OGM> ();
		hiscore.text = "HiScore- "+ogm.frogScore.ToString ("0");
		gameOVER = false;
		ingame = false;
		timer = 60; 
		InvokeRepeating ("StartUI", 1, 1);
	}
Exemple #10
0
	void Awake(){
		if (ogm == null) {
			DontDestroyOnLoad (gameObject);
			ogm = this;
		} else if (ogm != this) {
			Destroy(gameObject);
		}
	}
Exemple #11
0
	// Use this for initialization
	void Start () {
		ogm = GameObject.Find ("_OGM").GetComponent<OGM> ();
		gameOVER = false;
		ingame = false;
		timer = 60; 
		InvokeRepeating ("StartUI", 1, 1);
		InvokeRepeating("StartUI2",7.5f, 1);
	}
        public override void RemoveAll(Relationship relationship, OGM item, DateTime?moment, bool timedependent)
        {
            Dictionary <string, object?> parameters = new Dictionary <string, object?>();

            parameters.Add("key", item.GetKey());

            DirectionEnum direction = relationship.ComputeDirection(item.GetEntity());
            string        match     = (direction == DirectionEnum.Out) ? "MATCH (item:{0})<-[r:{1}]-(out)" : "MATCH (item:{0})-[r:{1}]->(out)";
            Entity        outEntity = (direction == DirectionEnum.Out) ? relationship.InEntity : relationship.OutEntity;

            string condition = string.Join(" OR ", outEntity.GetDbNames("out"));

            if (timedependent)
            {
                parameters.Add("moment", Conversion <DateTime, long> .Convert(moment ?? DateTime.MinValue));

                // End Current
                string cypher = string.Format(
                    match + " WHERE ({2}) and item.{3} = {{key}} and (r.{5} > {{moment}} OR r.{5} IS NULL) AND (r.{4} <={{moment}} OR r.{4} IS NULL) SET r.EndDate = {{moment}}",
                    item.GetEntity().Label.Name,
                    relationship.Neo4JRelationshipType,
                    condition,
                    item.GetEntity().Key.Name,
                    relationship.StartDate,
                    relationship.EndDate);

                Transaction.RunningTransaction.Run(cypher, parameters);

                // Remove Future
                cypher = string.Format(
                    match + " WHERE ({2}) and item.{3} = {{key}} and r.{4} > {{moment}} DELETE r",
                    item.GetEntity().Label.Name,
                    relationship.Neo4JRelationshipType,
                    condition,
                    item.GetEntity().Key.Name,
                    relationship.StartDate);

                Transaction.RunningTransaction.Run(cypher, parameters);
                //IResult result = trans.Run(cypher, parameters);
                //if (result.Summary.Counters.RelationshipsDeleted == 0)
                //    throw new ApplicationException($"Unable to delete all time dependent future relationships '{relationship.Neo4JRelationshipType}' related to {item.GetEntity().Label.Name}({item.GetKey()}).");
            }
            else
            {
                string cypher = string.Format(
                    match + " WHERE ({2}) and item.{3} = {{key}} DELETE r",
                    item.GetEntity().Label.Name,
                    relationship.Neo4JRelationshipType,
                    condition,
                    item.GetEntity().Key.Name);

                Transaction.RunningTransaction.Run(cypher, parameters);

                //IResult result = trans.Run(cypher, parameters);
                //if (result.Summary.Counters.RelationshipsDeleted == 0)
                //    throw new ApplicationException($"Unable to remove all relationships '{relationship.Neo4JRelationshipType}' related to {item.GetEntity().Label.Name}({item.GetKey()}).");
            }
        }
Exemple #13
0
	// Use this for initialization
	void Start () {
		pc = GameObject.Find ("OVRCameraRig");
		ogm = GameObject.Find ("_OGM").GetComponent<OGM> ();
		hiscore.text = "HiScore- "+ogm.sharkScore.ToString ("0");
		underwater = true;
		defaultFogColor = RenderSettings.fogColor;
		defaultFogDensity = RenderSettings.fogDensity;
		
	}
        private void Checks(Relationship relationship, OGM inItem, OGM outItem)
        {
            if (inItem.GetKey() == null || outItem.GetKey() == null)
            {
                throw new NotImplementedException("Entity should have key to participate in relationships.");
            }

            if (inItem.PersistenceState == PersistenceState.New || outItem.PersistenceState == PersistenceState.New)
            {
                throw new NotImplementedException("New entities should be saved first before it can participate in relationships.");
            }
        }
Exemple #15
0
        internal NodeEventArgs RaiseOnNodeDelete(Transaction trans, OGM sender, string cypher, Dictionary <string, object?> parameters, ref Dictionary <string, object?>?customState)
        {
            NodeEventArgs args = new NodeEventArgs(EventTypeEnum.OnNodeDelete, trans, sender, cypher, parameters, customState);

            if (!trans.FireGraphEvents)
            {
                return(args);
            }

            onNodeDelete?.Invoke(this, args);

            return(args);
        }
        private void Checks(Entity entity, OGM item)
        {
            //if (!item.GetEntity().IsSelfOrSubclassOf(entity))
            //    throw new NotImplementedException($"{item.GetEntity().Name} should inherit {entity.Name}.");

            if (item.GetKey() is null)
            {
                throw new NotImplementedException("Entity should have key to participate in relationships.");
            }

            if (item.PersistenceState == PersistenceState.New)
            {
                throw new NotImplementedException("New entities should be saved first before it can participate in relationships.");
            }
        }
        public override void Add(Relationship relationship, OGM inItem, OGM outItem, DateTime?moment, bool timedependent)
        {
            Transaction trans = Transaction.RunningTransaction;

            Checks(relationship, inItem, outItem);

            if (timedependent)
            {
                Add(trans, relationship, inItem, outItem, moment ?? Conversion.MinDateTime);
            }
            else
            {
                Add(trans, relationship, inItem, outItem);
            }

            relationship.RaiseOnRelationCreated(trans);
        }
Exemple #18
0
        private protected void ExecuteAction(ClearRelationshipsAction action)
        {
            if (DbTransaction != null)
            {
                DbTransaction?.Register(action);
            }
            else
            {
                foreach (Property property in GetEntity().Properties.Where(item => item.PropertyType != PropertyType.Attribute))
                {
                    if (property.ForeignProperty == null)
                    {
                        continue;
                    }

                    IEnumerable <OGM> instances;
                    object            value = property.GetValue(this, null);
                    if (property.PropertyType == PropertyType.Lookup)
                    {
                        instances = new OGM[] { (OGM)value }
                    }
                    ;
                    else
                    {
                        instances = (IEnumerable <OGM>)value;
                    }

                    foreach (OGM instance in instances)
                    {
                        if (property.ForeignProperty.PropertyType == PropertyType.Lookup)
                        {
                            property.ForeignProperty.SetValue(instance, null);
                        }
                        else
                        {
                            EntityCollectionBase collection = (EntityCollectionBase)property.ForeignProperty.GetValue(instance, null);
                            action.ExecuteInMemory(collection);
                        }
                    }
                    property.SetValue(this, null);
                }
            }
        }
        public override void Add(Relationship relationship, OGM inItem, OGM outItem, DateTime?moment, bool timedependent)
        {
            Transaction trans = Transaction.RunningTransaction;

            Checks(relationship, inItem, outItem);

            string match = string.Format("MATCH (in:{0}) WHERE in.{1} = {{inKey}} \r\n MATCH (out:{2}) WHERE out.{3} = {{outKey}}",
                                         inItem.GetEntity().Label.Name,
                                         inItem.GetEntity().Key.Name,
                                         outItem.GetEntity().Label.Name,
                                         outItem.GetEntity().Key.Name);
            string create = string.Format("MERGE (in)-[outr:{0}]->(out) ON CREATE SET outr.CreationDate = {{{1}}} SET outr += {{node}}", relationship.Neo4JRelationshipType, relationship.CreationDate);

            Dictionary <string, object?> parameters = new Dictionary <string, object?>();

            parameters.Add("inKey", inItem.GetKey());
            parameters.Add("outKey", outItem.GetKey());

            Dictionary <string, object> node = new Dictionary <string, object>();

            parameters.Add(relationship.CreationDate, Conversion <DateTime, long> .Convert(trans.TransactionDate));
            if (timedependent)
            {
                DateTime startDate = moment.HasValue ? moment.Value : DateTime.MinValue;
                node.Add(relationship.StartDate, Conversion <DateTime, long> .Convert(startDate));
                node.Add(relationship.EndDate, Conversion <DateTime, long> .Convert(DateTime.MaxValue));
            }

            parameters.Add("node", node);

            string query = match + "\r\n" + create;

            relationship.RaiseOnRelationCreate(trans);

            RawResult result = trans.Run(query, parameters);

            relationship.RaiseOnRelationCreated(trans);

            //if (result.Summary.Counters.RelationshipsCreated == 0)
            //    throw new ApplicationException($"Unable to create relationship '{relationship.Neo4JRelationshipType}' between {inItem.GetEntity().Label.Name}({inItem.GetKey()}) and {outItem.GetEntity().Label.Name}({outItem.GetKey()})");
        }
Exemple #20
0
	void Reset(){
		ogm = GameObject.Find ("_OGM").GetComponent<OGM> ();
		if (whichScore == 1) {
			GetComponent<Text>().text = "Top Score- "+ogm.sharkScore.ToString ("0");
		}
		if (whichScore == 2) {
			GetComponent<Text>().text = "Top Score- "+ogm.frogScore.ToString ("0");
		}		
		if (whichScore == 3) {
			GetComponent<Text>().text = "Top Score- "+ogm.castleScore.ToString ("0");
		}
		if (whichScore == 4) {
			GetComponent<Text>().text = "Top Score- "+ogm.skyScore.ToString ("0");
		}
		if (whichScore == 5) {
			GetComponent<Text>().text = "Top Score- "+ogm.pongScore.ToString ("0");
		}
		if (whichScore == 6) {
			GetComponent<Text>().text = "Top Score- "+ogm.fruitScore.ToString ("0");
		}
	}
Exemple #21
0
        public override void Load(OGM item)
        {
            Transaction trans = Transaction.RunningTransaction;

            string returnStatement = " RETURN node";
            string match           = string.Format("MATCH (node:{0}) WHERE node.{1} = {{key}}", item.GetEntity().Label.Name, item.GetEntity().Key.Name);
            Dictionary <string, object?> parameters = new Dictionary <string, object?>();

            parameters.Add("key", item.GetKey());

            Dictionary <string, object?>?customState = null;
            var args = item.GetEntity().RaiseOnNodeLoading(trans, item, match + returnStatement, parameters, ref customState);

            var result = trans.Run(args.Cypher, args.Parameters);

            RawRecord record = result.FirstOrDefault();

            if (record == null)
            {
                item.PersistenceState = PersistenceState.DoesntExist;
                return;
            }

            RawNode loaded = record["node"].As <RawNode>();

            args.Id     = loaded.Id;
            args.Labels = loaded.Labels;
            // HACK: To make it faster we do not copy/replicate the Dictionary here, but it means someone
            //       could be changing the INode content from within an event. Possibly dangerous, but
            //       turns out the Neo4j driver can deal with it ... for now ...
            args = item.GetEntity().RaiseOnNodeLoaded(trans, args, loaded.Id, loaded.Labels, (Dictionary <string, object?>)loaded.Properties);

            if (item.PersistenceState == PersistenceState.HasUid || item.PersistenceState == PersistenceState.Loaded)
            {
                item.SetData(args.Properties !);
                item.PersistenceState = PersistenceState.Loaded;
            }
        }
        public override Dictionary <OGM, CollectionItemList> Load(IEnumerable <OGM> parents, Core.EntityCollectionBase target)
        {
            if (parents.Count() == 0)
            {
                return(new Dictionary <OGM, CollectionItemList>());
            }

            Dictionary <object, OGM> parentDict = new Dictionary <object, OGM>();

            foreach (OGM parent in parents)
            {
                object?key = parent.GetKey();
                if (key is null)
                {
                    continue;
                }

                if (!parentDict.ContainsKey(key))
                {
                    parentDict.Add(key, parent);
                }
            }

            string matchClause = string.Empty;

            if (target.Direction == DirectionEnum.In)
            {
                matchClause = "MATCH ({0})-[rel:{2}]->({3})";
            }
            else if (target.Direction == DirectionEnum.Out)
            {
                matchClause = "MATCH ({0})<-[rel:{2}]-({3})";
            }

            string whereClause  = " WHERE node.{1} in ({{keys}}) ";
            string returnClause = " RETURN node.{1} as ParentKey, out.{4} as ItemKey ";

            if (target.Relationship.IsTimeDependent)
            {
                returnClause = $" RETURN node.{{1}} as ParentKey, out.{{4}} as ItemKey, rel.{target.Relationship.StartDate} as StartDate, rel.{target.Relationship.EndDate} as EndDate";
            }

            Entity targetEntity = target.ForeignEntity;

            string[] nodeNames = target.Parent.GetEntity().GetDbNames("node");
            string[] outNames  = targetEntity.GetDbNames("out");

            if (nodeNames.Length > 1 && outNames.Length > 1)
            {
                throw new InvalidOperationException("Both ends are virtual entities, this is too expensive to query...");
            }

            List <string> fullMatch = new List <string>();

            for (int nodeIndex = 0; nodeIndex < nodeNames.Length; nodeIndex++)
            {
                for (int outIndex = 0; outIndex < outNames.Length; outIndex++)
                {
                    string match = string.Format(string.Concat(matchClause, whereClause, returnClause),
                                                 nodeNames[nodeIndex],
                                                 target.ParentEntity.Key.Name,
                                                 target.Relationship.Neo4JRelationshipType,
                                                 outNames[outIndex],
                                                 targetEntity.Key.Name);

                    fullMatch.Add(match);
                }
            }

            Dictionary <string, object?> parameters = new Dictionary <string, object?>();

            parameters.Add("keys", parents.Select(item => item.GetKey()).ToArray());

            if (parents.Any(parent => parent.GetEntity() != target.Parent.GetEntity()))
            {
                throw new InvalidOperationException("This code should only load collections of the same concrete parent class.");
            }

            var result = Transaction.RunningTransaction.Run(string.Join(" UNION ", fullMatch), parameters);
            List <RelationshipIndex> indexCache = new List <RelationshipIndex>();

            foreach (var record in result)
            {
                DateTime?startDate = null;
                DateTime?endDate   = null;

                if (target.Relationship.IsTimeDependent)
                {
                    startDate = (record.Values["StartDate"] != null) ? Conversion <long, DateTime> .Convert((long)record.Values["StartDate"].As <long>()) : (DateTime?)null;

                    endDate = (record.Values["EndDate"] != null) ? Conversion <long, DateTime> .Convert((long)record.Values["EndDate"].As <long>()) : (DateTime?)null;
                }

                indexCache.Add(new RelationshipIndex(record.Values["ParentKey"].As <object>(), record.Values["ItemKey"].As <object>(), startDate, endDate));
            }

            Dictionary <object, List <RawNode> > itemsCache = Load(targetEntity, indexCache.Select(r => r.TargetEntityKey));

            List <CollectionItem> items = new List <CollectionItem>();

            foreach (var index in indexCache)
            {
                OGM parent = parentDict[index.SourceEntityKey];
                foreach (var item in itemsCache[index.TargetEntityKey])
                {
                    OGM?child = ReadNode(parent, targetEntity, item);
                    items.Add(target.NewCollectionItem(parent, child, index.StartDate, index.EndDate));
                }
            }

            return(CollectionItemList.Get(items));
        }
 public DynamicEntityCollection(OGM parent, Property property) : base(parent, property)
 {
 }
Exemple #24
0
 static bool HasChanges(OGM entity)
 {
     return(entity.PersistenceState != PersistenceState.New && entity.PersistenceState != PersistenceState.Delete && entity.PersistenceState != PersistenceState.HasUid && entity.PersistenceState != PersistenceState.DoesntExist && entity.PersistenceState != PersistenceState.ForceDelete && entity.PersistenceState != PersistenceState.Loaded);
 }
        private OGM ReadNode(OGM parent, Entity targetEntity, RawNode node)
        {
            object?keyObject = null;

            if (targetEntity.Key != null)
            {
                node.Properties.TryGetValue(targetEntity.Key.Name, out keyObject);
            }

            string?typeName = null;

            if (targetEntity.NodeType != null)
            {
                object?nodeType;
                if (node.Properties.TryGetValue(targetEntity.NodeType.Name, out nodeType))
                {
                    typeName = nodeType as string;
                }
            }

            if (typeName == null)
            {
                if (!targetEntity.IsAbstract)
                {
                    typeName = targetEntity.Name;
                }
                else
                {
                    typeName = targetEntity.GetConcreteClasses().Where(e => node.Labels.Contains(e.Label.Name)).Select(e => e.Name).FirstOrDefault();
                }
            }

            if (typeName == null)
            {
                throw new NotSupportedException("The concrete type of the node could not be determined.");
            }

            OGM?item = null;

            if (keyObject != null)
            {
                item = Transaction.RunningTransaction.GetEntityByKey(typeName, keyObject);
                if (item != null &&
                    (item.PersistenceState == PersistenceState.HasUid
                     ||
                     item.PersistenceState == PersistenceState.Loaded))
                {
#pragma warning disable CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types.
                    item.SetData(node.Properties);
#pragma warning restore CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types.
                    item.PersistenceState = PersistenceState.Loaded;
                }

                if (item == null)
                {
                    if (targetEntity.Parent.IsUpgraded)
                    {
                        Type type = typeCache.TryGetOrAdd(typeName, key =>
                        {
                            type = parent.GetType().Assembly.GetTypes().FirstOrDefault(x => x.Name == typeName);
                            if (type == null)
                            {
                                throw new NotSupportedException();
                            }

                            return(type);
                        });
                        item = (OGM)Activator.CreateInstance(type) !;
                    }
                    else
                    {
                        item = new DynamicEntity(targetEntity, Parser.ShouldExecute);
                    }

#pragma warning disable CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types.
                    item.SetData(node.Properties);
#pragma warning restore CS8620 // Argument cannot be used for parameter due to differences in the nullability of reference types.
                    item.SetKey(keyObject);
                    item.PersistenceState = PersistenceState.Loaded;
                }
            }

            if (item is null)
            {
                throw new InvalidOperationException("Could not load object from node properties.");
            }

            return(item);
        }
        public override IEnumerable <CollectionItem> Load(OGM parent, Core.EntityCollectionBase target)
        {
            Entity targetEntity = target.ForeignEntity;

            string[] nodeNames = target.Parent.GetEntity().GetDbNames("node");
            string[] outNames  = targetEntity.GetDbNames("out");

            if (nodeNames.Length > 1 && outNames.Length > 1)
            {
                throw new InvalidOperationException("Both ends are virtual entities, this is too expensive to query...");
            }

            List <string> fullMatch = new List <string>();

            for (int nodeIndex = 0; nodeIndex < nodeNames.Length; nodeIndex++)
            {
                for (int outIndex = 0; outIndex < outNames.Length; outIndex++)
                {
                    string pattern = string.Empty;
                    if (target.Direction == DirectionEnum.In)
                    {
                        pattern = "MATCH ({0})-[rel:{2}]->({3}) WHERE node.{1} = {{key}} RETURN out, rel";
                    }
                    else if (target.Direction == DirectionEnum.Out)
                    {
                        pattern = "MATCH ({0})<-[rel:{2}]-({3}) WHERE node.{1} = {{key}} RETURN out, rel";
                    }

                    string match = string.Format(pattern,
                                                 nodeNames[nodeIndex],
                                                 target.ParentEntity.Key.Name,
                                                 target.Relationship.Neo4JRelationshipType,
                                                 outNames[outIndex]);

                    fullMatch.Add(match);
                }
            }

            Dictionary <string, object?> parameters2 = new Dictionary <string, object?>();

            parameters2.Add("key", parent.GetKey());

            List <CollectionItem> items = new List <CollectionItem>();
            var result = Transaction.RunningTransaction.Run(string.Join(" UNION ", fullMatch), parameters2);

            foreach (var record in result)
            {
                RawNode node = record.Values["out"].As <RawNode>();
                if (node is null)
                {
                    continue;
                }

                OGM             item = ReadNode(parent, targetEntity, node);
                RawRelationship rel  = record.Values["rel"].As <RawRelationship>();

                DateTime?startDate = null;
                DateTime?endDate   = null;

                if (target.Relationship.IsTimeDependent)
                {
                    object?value;
                    if (rel.Properties.TryGetValue(target.Relationship.StartDate, out value))
                    {
                        startDate = Conversion <long, DateTime> .Convert((long)value);
                    }
                    if (rel.Properties.TryGetValue(target.Relationship.EndDate, out value))
                    {
                        endDate = Conversion <long, DateTime> .Convert((long)value);
                    }
                }

                items.Add(target.NewCollectionItem(parent, item, startDate, endDate));
            }

            return(items);
        }
Exemple #27
0
        public override void Insert(OGM item)
        {
            Transaction trans  = Transaction.RunningTransaction;
            Entity      entity = item.GetEntity();

            string labels = string.Join(":", entity.GetBaseTypesAndSelf().Where(x => x.IsVirtual == false).Select(x => x.Label.Name));

            if (entity.RowVersion != null)
            {
                item.SetRowVersion(trans.TransactionDate);
            }

            IDictionary <string, object?> node = item.GetData();

            string create = string.Format("CREATE (inserted:{0} {{node}}) Return inserted", labels);

            if (entity.FunctionalId != null)
            {
                object?key = item.GetKey();
                if (key is null)
                {
                    string nextKey = string.Format("CALL blueprint41.functionalid.next('{0}') YIELD value as key", entity.FunctionalId.Label);
                    if (entity.FunctionalId.Format == IdFormat.Numeric)
                    {
                        nextKey = string.Format("CALL blueprint41.functionalid.nextNumeric('{0}') YIELD value as key", entity.FunctionalId.Label);
                    }

                    create = nextKey + "\r\n" + string.Format("CREATE (inserted:{0} {{node}}) SET inserted.{1} = key Return inserted", labels, entity.Key.Name);

                    node.Remove(entity.Key.Name);
                }
                else
                {
                    entity.FunctionalId.SeenUid(key.ToString() !);
                }
            }

            Dictionary <string, object?> parameters = new Dictionary <string, object?>();

            parameters.Add("node", node);

            Dictionary <string, object?>?customState = null;
            var args = entity.RaiseOnNodeCreate(trans, item, create, parameters, ref customState);

            var       result = trans.Run(args.Cypher, args.Parameters);
            RawRecord record = result.FirstOrDefault();

            if (record == null)
            {
                throw new InvalidOperationException($"Due to an unexpected state of the neo4j transaction, it seems impossible to insert the {entity.Name} at this time.");
            }

            RawNode inserted = record["inserted"].As <RawNode>();

            args.Id     = inserted.Id;
            args.Labels = inserted.Labels;
            // HACK: To make it faster we do not copy/replicate the Dictionary here, but it means someone
            //       could be changing the INode content from within an event. Possibly dangerous, but
            //       turns out the Neo4j driver can deal with it ... for now ...
            args.Properties = (Dictionary <string, object?>)inserted.Properties;
            args            = entity.RaiseOnNodeCreated(trans, args, inserted.Id, inserted.Labels, (Dictionary <string, object?>)inserted.Properties);

            item.SetData(args.Properties !);
            item.PersistenceState = PersistenceState.Persisted;
            Transaction.RunningTransaction.Register(entity.Name, item, true);
        }
        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...
            }
        }
        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()})");
                }
            }
        }
        public override void AddUnmanaged(Relationship relationship, OGM inItem, OGM outItem, DateTime?startDate, DateTime?endDate, bool fullyUnmanaged = false)
        {
            Transaction trans = Transaction.RunningTransaction;

            Checks(relationship, inItem, outItem);

            if (!fullyUnmanaged)
            {
                string find = string.Format(
                    "MATCH (in:{0})-[r:{1}]->(out:{2}) WHERE in.{3} = {{inKey}} and out.{4} = {{outKey}} and (r.{5} <= {{endDate}} OR r.{5} IS NULL) AND (r.{6} > {{startDate}} OR r.{6} IS NULL) RETURN min(COALESCE(r.{5}, {{MinDateTime}})) as MinStartDate, max(COALESCE(r.{6}, {{MaxDateTime}})) as MaxEndDate, count(r) as Count",
                    inItem.GetEntity().Label.Name,
                    relationship.Neo4JRelationshipType,
                    outItem.GetEntity().Label.Name,
                    inItem.GetEntity().Key.Name,
                    outItem.GetEntity().Key.Name,
                    relationship.StartDate,
                    relationship.EndDate);

                Dictionary <string, object?> parameters = new Dictionary <string, object?>();
                parameters.Add("inKey", inItem.GetKey());
                parameters.Add("outKey", outItem.GetKey());
                parameters.Add("startDate", Conversion <DateTime, long> .Convert(startDate ?? DateTime.MinValue));
                parameters.Add("endDate", Conversion <DateTime, long> .Convert(endDate ?? DateTime.MaxValue));
                parameters.Add("MinDateTime", Conversion <DateTime, long> .Convert(DateTime.MinValue));
                parameters.Add("MaxDateTime", Conversion <DateTime, long> .Convert(DateTime.MaxValue));

                RawResult result = trans.Run(find, parameters);
                RawRecord record = result.FirstOrDefault();
                int       count  = record["Count"].As <int>();
                if (count > 0)
                {
                    DateTime?minStartDate = Conversion <long?, DateTime?> .Convert(record["MinStartDate"].As <long?>());

                    DateTime?maxEndDate = Conversion <long?, DateTime?> .Convert(record["MaxEndDate"].As <long?>());

                    if (startDate > minStartDate)
                    {
                        startDate = minStartDate ?? DateTime.MinValue;
                    }

                    if (endDate < maxEndDate)
                    {
                        endDate = maxEndDate ?? DateTime.MaxValue;
                    }
                }

                string delete = string.Format(
                    "MATCH (in:{0})-[r:{1}]->(out:{2}) WHERE in.{3} = {{inKey}} and out.{4} = {{outKey}} and (r.{5} <= {{endDate}}) AND (r.{6} > {{startDate}}) DELETE r",
                    inItem.GetEntity().Label.Name,
                    relationship.Neo4JRelationshipType,
                    outItem.GetEntity().Label.Name,
                    inItem.GetEntity().Key.Name,
                    outItem.GetEntity().Key.Name,
                    relationship.StartDate,
                    relationship.EndDate);

                trans.Run(delete, parameters);
            }

            string match = string.Format("MATCH (in:{0}) WHERE in.{1} = {{inKey}} MATCH (out:{2}) WHERE out.{3} = {{outKey}}",
                                         inItem.GetEntity().Label.Name,
                                         inItem.GetEntity().Key.Name,
                                         outItem.GetEntity().Label.Name,
                                         outItem.GetEntity().Key.Name);
            string create = string.Format("CREATE (in)-[outr:{0} {{node}}]->(out)", relationship.Neo4JRelationshipType);

            Dictionary <string, object> node = new Dictionary <string, object>();

            node.Add(relationship.CreationDate, Conversion <DateTime, long> .Convert(trans.TransactionDate));
            if (relationship.IsTimeDependent)
            {
                node.Add(relationship.StartDate, Conversion <DateTime, long> .Convert(startDate ?? DateTime.MinValue));
                node.Add(relationship.EndDate, Conversion <DateTime, long> .Convert(endDate ?? DateTime.MaxValue));
            }

            Dictionary <string, object?> parameters2 = new Dictionary <string, object?>();

            parameters2.Add("inKey", inItem.GetKey());
            parameters2.Add("outKey", outItem.GetKey());
            parameters2.Add("node", node);

            string query = match + "\r\n" + create;

            relationship.RaiseOnRelationCreate(trans);

            trans.Run(query, parameters2);

            relationship.RaiseOnRelationCreated(trans);
        }
Exemple #31
0
 protected bool RelationshipExists(Property foreignProperty, OGM instance)
 {
     return(RunningTransaction.NodePersistenceProvider.RelationshipExists(foreignProperty, instance));
 }