Beispiel #1
0
        private static IEnumerable <MemberBinding> ExpansionMemberBindings(Expression dto, QueryTree tree, IClassCache cache)
        {
            var vertex        = tree.Root;
            var classInfo     = cache.Get(vertex.Value.TypeId);
            var outgoingEdges = tree.Children.Select(c => c.Item1);

            // Bind all the non-expandable types.
            foreach (var prop in BindingsForProperties(vertex, cache, dto))
            {
                yield return(prop);
            }

            // navigation properties
            foreach (var prop in vertex.Value.Properties.Where(x => x.IsNavigationProperty))
            {
                var propertyInfo     = classInfo.NavigationProperties.First(x => x.Name == prop.Name);
                var navigationVertex = outgoingEdges.FirstOrDefault(x => x.Value.Name == prop.Name).To;
                var navigationTree   = tree.Children.First(c => c.Item1.To == navigationVertex).Item2;
                yield return(Expression.Bind(propertyInfo, GetExpandExpression(Expression.PropertyOrField(dto, prop.Name), navigationTree, cache)));
            }

            // // collections
            foreach (var prop in vertex.Value.Properties.Where(x => x.IsCollection))
            {
                var propertyInfo = classInfo.Collections.First(x => x.Name == prop.Name);

                if (!propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GenericTypeArguments.Length != 1)
                {
                    continue;
                }

                var collectionVertex = outgoingEdges.Single(x => x.Value.Name == prop.Name).To;
                var navigationTree   = tree.Children.First(c => c.Item1.To == collectionVertex).Item2;
                var collectionType   = cache.GetTypeFromId(collectionVertex.Value.TypeId);

                var listType = typeof(List <>).MakeGenericType(collectionType);

                var childrenParameter = Expression.Parameter(collectionType, prop.Name);
                var childrenProperty  = Expression.PropertyOrField(dto, prop.Name);
                var select            = ExpressionBuilder.BuildSelectExpression(collectionType,
                                                                                childrenProperty,
                                                                                childrenParameter, GetExpandExpression(childrenParameter, navigationTree, cache));
                var list = Expression.Condition(
                    Expression.Equal(childrenProperty, Expression.Constant(null)),
                    Expression.New(listType.GetConstructor(Array.Empty <Type>()), Array.Empty <Expression>()),
                    Expression.New(listType.GetConstructor(new Type[] { listType }), select)
                    );
                yield return(Expression.Bind(propertyInfo, list));
            }
        }
Beispiel #2
0
        private static GraphSchema CreateFromGeneric <TDto>(IClassCache cache)
        {
            var vertices = new List <StatefulVertex <ClassInfo> >();
            var edges    = new List <Edge>();
            var types    = new HashSet <Type>();

            // Helper funcs
            // get the class info from type via the cache.
            ClassInfoUtility GetClassInfoFromType(Type t)
            {
                var hash = t.GetHashCode();

                if (cache.HasKey(hash))
                {
                    return(cache.Get(hash));
                }
                return(cache.GetOrAdd(t));
            }

            bool VerticesContainType(Type type) => vertices.Any(v => v.Vertex.Value.TypeId == type.GetHashCode());

            StatefulVertex <ClassInfo> GetOrAddVertex(Type type)
            {
                StatefulVertex <ClassInfo> vertex = null;

                if (VerticesContainType(type))
                {
                    vertex = vertices.First(v => v.Vertex.Value.TypeId == type.GetHashCode());
                }
                else
                {
                    vertex = new StatefulVertex <ClassInfo>(new Vertex(new ClassInfo(GetClassInfoFromType(type))), type);
                    vertices.Add(vertex);
                    types.Add(type);
                }
                return(vertex);
            }

            // initialize root.
            GetOrAddVertex(typeof(TDto));

            while (vertices.Any(v => v.Color != StatefulVertexStateType.Discovered))
            {
                var vertex = vertices.First(v => v.Color == StatefulVertexStateType.UnReached);
                vertex.Color = StatefulVertexStateType.Identified;

                var classInfo = GetClassInfoFromType(vertex.Type);
                var tentativeConnectionToType = new List <Edge>();

                void EstablishConnection(Type connectionToType, Property property)
                {
                    var toVertex = GetOrAddVertex(connectionToType);
                    var edge     = new Edge(vertex.Vertex as Vertex, toVertex.Vertex as Vertex, property);

                    if (!edges.Contains(edge))
                    {
                        edges.Add(edge);
                    }
                }

                foreach (var childNavigationProperty in vertex.Vertex.Value.Properties.Where(p => p.IsNavigationProperty))
                {
                    var type = classInfo.NavigationProperties.FirstOrDefault(x => x.Name == childNavigationProperty.Name)?.PropertyType;
                    if (type is null)
                    {
                        continue;
                    }
                    EstablishConnection(type, childNavigationProperty);
                }
                foreach (var childCollection in vertex.Vertex.Value.Properties.Where(p => p.IsCollection))
                {
                    var type = classInfo.Collections.FirstOrDefault(x => x.Name == childCollection.Name)?.PropertyType.GetGenericArguments()[0];
                    if (type is null)
                    {
                        continue;
                    }
                    EstablishConnection(type, childCollection);
                }

                vertex.Color = StatefulVertexStateType.Discovered;
            }

            return(new GraphSchema(vertices.Select(v => v.Vertex as Vertex), edges));
        }