public async Task <IEnumerable <LiveDbObject <T> > > ReturnAsync() { internalQ.Append("WITH "); for (int i = 0; i < PathCount; i++) { if (i > 0) { internalQ.Append(" + "); } internalQ.Append($"collect(p{i})"); } internalQ.Append($" AS paths{Environment.NewLine}"); internalQ.Append($"UNWIND paths AS ret{Environment.NewLine}"); internalQ = internalQ.AppendLine("RETURN ret as json"); using (IDriver driver = clientFactory()) { Query q = new Query(internalQ.ToString()); IResultCursor resultCursor = await driver.AsyncSession().RunAsync(q); List <IRecord> results = await resultCursor.ToListAsync(); Dictionary <string, INeo4jNode> nodeHeap = new Dictionary <string, INeo4jNode>(); var raw = results.SelectMany(x => { var h = x["json"].As <IPath>(); List <INeo4jNode> nodes = h.Nodes.Select(a => { INeo4jNode parentInstance; if (!nodeHeap.TryGetValue(a["Id"].ToString(), out parentInstance)) { Type parentType = ReflectionCache.BuildType(a["__type__"].As <string>()); parentInstance = Activator.CreateInstance(parentType) as INeo4jNode; ReflectionCache.Type typeData = ReflectionCache.GetTypeData(parentType); foreach (KeyValuePair <string, object> k in a.Properties) { if (typeData.props.TryGetValue(k.Key, out ReflectionCache.Property prop)) { prop.PushValue(parentInstance, DBOps.Neo4jDecode(k.Value, prop.info.PropertyType)); } } nodeHeap.Add(a["Id"].ToString(), parentInstance); } return(parentInstance); }).ToList(); return(h.Relationships .Select((x, i) => (nodes[i].Id, nodes[i + 1].Id, x.Type)) .Cast <(string parentID, string childID, string relationship)>()); }).ToList(); var withProps = raw.Select(x => (x.Item1, x.Item2, ReflectionCache.GetTypeData(nodeHeap[x.Item1]).props .Where(y => y.Key == x.Item3 || ( y.Value.neo4JAttributes.Where(x => x is DbNameAttribute).Any() && y.Value.neo4JAttributes.Select(x => x as DbNameAttribute).Where(x => x != null).FirstOrDefault()?.Name == x.Item3 ) ) .SingleOrDefault() .Value )).ToList(); var groupDedupe = withProps.GroupBy(x => x.Item1 + x.Item2).Select(x => x.First()).GroupBy(x => (x.Value, x.Item1)); foreach (var g in groupDedupe) { if (!g.Key.Value.isCollection) { var v = g.Single(); v.Item3.PushValue(nodeHeap[v.Item1], nodeHeap[v.Item2]); } else { System.Type t = g.Key.Value.info.PropertyType.GetGenericArguments()[0]; System.Type lstT = typeof(List <>).MakeGenericType(t); ConstructorInfo cotr = lstT.GetConstructors().Where(x => x.GetParameters().Length == 0).Single(); Type enu = typeof(Enumerable); MethodInfo selct = enu.GetMethods() .Where(x => x.Name == "Select") .OrderBy(x => x.GetParameters().Length) .First() .MakeGenericMethod(typeof(string), t); MethodInfo toLst = enu.GetMethods() .Where(x => x.Name == "ToList") .OrderBy(x => x.GetParameters().Length) .First() .MakeGenericMethod(t); Type ndhpTyp = nodeHeap.GetType(); ParameterExpression ndhp = Expression.Parameter(ndhpTyp, "ndhp"); ParameterExpression ky = Expression.Parameter(typeof(string), "ky"); var selExpr = Expression.Lambda( Expression.Convert(Expression.Property(ndhp, "Item", ky), t), ky ); var expr = Expression.Lambda( Expression.Call( null, toLst, Expression.Call( null, selct, Expression.Constant(g.Select(x => x.Item2)), selExpr ) ), ndhp ); object psh = expr.Compile().DynamicInvoke(nodeHeap); g.Key.Item1.PushValue(nodeHeap[g.Key.Item2], psh); } } var ret = nodeHeap .Select(x => x.Value) .Where(x => x is T) .Cast <T>() .Distinct() .Select(x => LiveDbObject <T> .Build(x, clientFactory, LiveObjectMode.LiveWrite | LiveObjectMode.DeferedRead)) .ToArray(); return(ret); } }