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 override Dictionary <OGM, CollectionItemList> Load(IEnumerable <OGM> parents, Core.EntityCollectionBase target) { if (parents.Count() == 0) { return(new Dictionary <OGM, CollectionItemList>()); } HashSet <OGM> parentHashset = new HashSet <OGM>(parents); 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 as Parent, out as Item "; if (target.Relationship.IsTimeDependent) { returnClause = $" RETURN node as Parent, out as Item, 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]); 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."); } string cypher = string.Join(" UNION ", fullMatch); var result = Transaction.RunningTransaction.Run(cypher, parameters); List <CollectionItem> items = new List <CollectionItem>(); foreach (var record in result) { DateTime?startDate = null; DateTime?endDate = null; if (target.Relationship.IsTimeDependent) { startDate = (record.Values["StartDate"] is not null) ? Conversion <long, DateTime> .Convert((long)record.Values["StartDate"].As <long>()) : (DateTime?)null; endDate = (record.Values["EndDate"] is not null) ? Conversion <long, DateTime> .Convert((long)record.Values["EndDate"].As <long>()) : (DateTime?)null; } OGM?parent = target.Parent.GetEntity().Map(record.Values["Parent"].As <RawNode>(), NodeMapping.AsWritableEntity); OGM?item = targetEntity.Map(record.Values["Item"].As <RawNode>(), NodeMapping.AsWritableEntity); if (parent is null || item is null) { throw new NotSupportedException("The cypher query expected to have a parent node and a child node."); } if (parentHashset.Contains(parent)) { items.Add(target.NewCollectionItem(parent, item, startDate, endDate)); } } return(CollectionItemList.Get(items)); }