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); }
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)); }
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()); }
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); } }
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; }
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); } }
// 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); }
void Awake(){ if (ogm == null) { DontDestroyOnLoad (gameObject); ogm = this; } else if (ogm != this) { Destroy(gameObject); } }
// 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()})."); } }
// 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."); } }
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); }
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()})"); }
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"); } }
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) { }
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); }
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); }
protected bool RelationshipExists(Property foreignProperty, OGM instance) { return(RunningTransaction.NodePersistenceProvider.RelationshipExists(foreignProperty, instance)); }