private Expression CreateLambdaBodyInitializer(IDictionary <ResourceFieldAttribute, QueryLayer> selectors, ResourceContext resourceContext,
                                                       LambdaScope lambdaScope, bool lambdaAccessorRequiresTestForNull)
        {
            var propertySelectors = ToPropertySelectors(selectors, resourceContext, lambdaScope.Parameter.Type);

            MemberBinding[] propertyAssignments = propertySelectors.Select(selector => CreatePropertyAssignment(selector, lambdaScope)).Cast <MemberBinding>().ToArray();

            NewExpression newExpression = _resourceFactory.CreateNewExpression(lambdaScope.Accessor.Type);
            Expression    memberInit    = Expression.MemberInit(newExpression, propertyAssignments);

            if (lambdaScope.HasManyThrough != null)
            {
                MemberBinding outerPropertyAssignment = Expression.Bind(lambdaScope.HasManyThrough.RightProperty, memberInit);

                NewExpression outerNewExpression = _resourceFactory.CreateNewExpression(lambdaScope.HasManyThrough.ThroughType);
                memberInit = Expression.MemberInit(outerNewExpression, outerPropertyAssignment);
            }

            if (!lambdaAccessorRequiresTestForNull)
            {
                return(memberInit);
            }

            return(TestForNull(lambdaScope.Accessor, memberInit));
        }
예제 #2
0
        public override Expression VisitCollectionNotEmpty(CollectionNotEmptyExpression expression, Type argument)
        {
            Expression property = Visit(expression.TargetCollection, argument);

            Type elementType = CollectionConverter.TryGetCollectionElementType(property.Type);

            if (elementType == null)
            {
                throw new InvalidOperationException("Expression must be a collection.");
            }

            Expression predicate = null;

            if (expression.Filter != null)
            {
                var hasManyThrough     = expression.TargetCollection.Fields.Last() as HasManyThroughAttribute;
                var lambdaScopeFactory = new LambdaScopeFactory(_nameFactory, hasManyThrough);
                using LambdaScope lambdaScope = lambdaScopeFactory.CreateScope(elementType);

                var builder = new WhereClauseBuilder(property, lambdaScope, typeof(Enumerable), _nameFactory);
                predicate = builder.GetPredicateLambda(expression.Filter);
            }

            return(AnyExtensionMethodCall(elementType, property, predicate));
        }
        private Expression CreateCollectionInitializer(LambdaScope lambdaScope, PropertyInfo collectionProperty,
                                                       Type elementType, QueryLayer layer, LambdaScopeFactory lambdaScopeFactory)
        {
            MemberExpression propertyExpression = Expression.Property(lambdaScope.Accessor, collectionProperty);

            var builder = new QueryableBuilder(propertyExpression, elementType, typeof(Enumerable), _nameFactory,
                                               _resourceFactory, _resourceContextProvider, _entityModel, lambdaScopeFactory);

            Expression layerExpression = builder.ApplyQuery(layer);

            Type enumerableOfElementType = typeof(IEnumerable <>).MakeGenericType(elementType);
            Type typedCollection         = TypeHelper.ToConcreteCollectionType(collectionProperty.PropertyType);

            ConstructorInfo typedCollectionConstructor = typedCollection.GetConstructor(new[]
            {
                enumerableOfElementType
            });

            if (typedCollectionConstructor == null)
            {
                throw new Exception(
                          $"Constructor on '{typedCollection.Name}' that accepts '{enumerableOfElementType.Name}' not found.");
            }

            return(Expression.New(typedCollectionConstructor, layerExpression));
        }
        private Expression CreateCollectionInitializer(LambdaScope lambdaScope, PropertyInfo collectionProperty, Type elementType, QueryLayer layer,
                                                       LambdaScopeFactory lambdaScopeFactory)
        {
            MemberExpression propertyExpression = Expression.Property(lambdaScope.Accessor, collectionProperty);

            var builder = new QueryableBuilder(propertyExpression, elementType, typeof(Enumerable), _nameFactory, _resourceFactory, _resourceContextProvider,
                                               _entityModel, lambdaScopeFactory);

            Expression layerExpression = builder.ApplyQuery(layer);

            // Earlier versions of EF Core 3.x failed to understand `query.ToHashSet()`, so we emit `new HashSet(query)` instead.
            // Interestingly, EF Core 5 RC1 fails to understand `new HashSet(query)`, so we emit `query.ToHashSet()` instead.
            // https://github.com/dotnet/efcore/issues/22902

            if (EntityFrameworkCoreSupport.Version.Major < 5)
            {
                Type enumerableOfElementType = typeof(IEnumerable <>).MakeGenericType(elementType);
                Type typedCollection         = CollectionConverter.ToConcreteCollectionType(collectionProperty.PropertyType);

                ConstructorInfo typedCollectionConstructor = typedCollection.GetConstructor(enumerableOfElementType.AsArray());

                if (typedCollectionConstructor == null)
                {
                    throw new InvalidOperationException($"Constructor on '{typedCollection.Name}' that accepts '{enumerableOfElementType.Name}' not found.");
                }

                return(Expression.New(typedCollectionConstructor, layerExpression));
            }

            string operationName = CollectionConverter.TypeCanContainHashSet(collectionProperty.PropertyType) ? "ToHashSet" : "ToList";

            return(CopyCollectionExtensionMethodCall(layerExpression, operationName, elementType));
        }
 public IncludeClauseBuilder(Expression source, LambdaScope lambdaScope, ResourceContext resourceContext,
                             IResourceContextProvider resourceContextProvider)
     : base(lambdaScope)
 {
     _source                  = source ?? throw new ArgumentNullException(nameof(source));
     _resourceContext         = resourceContext ?? throw new ArgumentNullException(nameof(resourceContext));
     _resourceContextProvider = resourceContextProvider ?? throw new ArgumentNullException(nameof(resourceContextProvider));
 }
        protected virtual Expression ApplyFilter(Expression source, FilterExpression filter)
        {
            using LambdaScope lambdaScope = _lambdaScopeFactory.CreateScope(_elementType);

            var builder = new WhereClauseBuilder(source, lambdaScope, _extensionType, _nameFactory);

            return(builder.ApplyWhere(filter));
        }
        protected virtual Expression ApplyInclude(Expression source, IncludeExpression include, ResourceContext resourceContext)
        {
            using LambdaScope lambdaScope = _lambdaScopeFactory.CreateScope(_elementType);

            var builder = new IncludeClauseBuilder(source, lambdaScope, resourceContext, _resourceContextProvider);

            return(builder.ApplyInclude(include));
        }
        protected virtual Expression ApplyPagination(Expression source, PaginationExpression pagination)
        {
            using LambdaScope lambdaScope = _lambdaScopeFactory.CreateScope(_elementType);

            var builder = new SkipTakeClauseBuilder(source, lambdaScope, _extensionType);

            return(builder.ApplySkipTake(pagination));
        }
        protected virtual Expression ApplySort(Expression source, SortExpression sort)
        {
            using LambdaScope lambdaScope = _lambdaScopeFactory.CreateScope(_elementType);

            var builder = new OrderClauseBuilder(source, lambdaScope, _extensionType);

            return(builder.ApplyOrderBy(sort));
        }
예제 #10
0
        public WhereClauseBuilder(Expression source, LambdaScope lambdaScope, Type extensionType)
            : base(lambdaScope)
        {
            ArgumentGuard.NotNull(source, nameof(source));
            ArgumentGuard.NotNull(extensionType, nameof(extensionType));

            _source        = source;
            _extensionType = extensionType;
        }
예제 #11
0
        protected virtual Expression ApplyProjection(Expression source, IDictionary <ResourceFieldAttribute, QueryLayer> projection,
                                                     ResourceContext resourceContext)
        {
            using LambdaScope lambdaScope = _lambdaScopeFactory.CreateScope(_elementType);

            var builder = new SelectClauseBuilder(source, lambdaScope, _entityModel, _extensionType, _nameFactory, _resourceFactory, _resourceContextProvider);

            return(builder.ApplySelect(projection, resourceContext));
        }
 public SelectClauseBuilder(Expression source, LambdaScope lambdaScope, IModel entityModel, Type extensionType,
                            LambdaParameterNameFactory nameFactory, IResourceFactory resourceFactory, IResourceContextProvider resourceContextProvider)
     : base(lambdaScope)
 {
     _source                  = source ?? throw new ArgumentNullException(nameof(source));
     _entityModel             = entityModel ?? throw new ArgumentNullException(nameof(entityModel));
     _extensionType           = extensionType ?? throw new ArgumentNullException(nameof(extensionType));
     _nameFactory             = nameFactory ?? throw new ArgumentNullException(nameof(nameFactory));
     _resourceFactory         = resourceFactory ?? throw new ArgumentNullException(nameof(resourceFactory));
     _resourceContextProvider = resourceContextProvider ?? throw new ArgumentNullException(nameof(resourceContextProvider));
 }
예제 #13
0
        public WhereClauseBuilder(Expression source, LambdaScope lambdaScope, Type extensionType, LambdaParameterNameFactory nameFactory)
            : base(lambdaScope)
        {
            ArgumentGuard.NotNull(source, nameof(source));
            ArgumentGuard.NotNull(extensionType, nameof(extensionType));
            ArgumentGuard.NotNull(nameFactory, nameof(nameFactory));

            _source        = source;
            _extensionType = extensionType;
            _nameFactory   = nameFactory;
        }
        public IncludeClauseBuilder(Expression source, LambdaScope lambdaScope, ResourceContext resourceContext,
                                    IResourceContextProvider resourceContextProvider)
            : base(lambdaScope)
        {
            ArgumentGuard.NotNull(source, nameof(source));
            ArgumentGuard.NotNull(resourceContext, nameof(resourceContext));
            ArgumentGuard.NotNull(resourceContextProvider, nameof(resourceContextProvider));

            _source                  = source;
            _resourceContext         = resourceContext;
            _resourceContextProvider = resourceContextProvider;
        }
        private MemberAssignment CreatePropertyAssignment(PropertySelector selector, LambdaScope lambdaScope)
        {
            MemberExpression propertyAccess = Expression.Property(lambdaScope.Accessor, selector.Property);

            Expression assignmentRightHandSide = propertyAccess;

            if (selector.NextLayer != null)
            {
                HasManyThroughAttribute hasManyThrough = selector.OriginatingField as HasManyThroughAttribute;
                var lambdaScopeFactory = new LambdaScopeFactory(_nameFactory, hasManyThrough);

                assignmentRightHandSide = CreateAssignmentRightHandSideForLayer(selector.NextLayer, lambdaScope, propertyAccess,
                                                                                selector.Property, lambdaScopeFactory);
            }

            return(Expression.Bind(selector.Property, assignmentRightHandSide));
        }
        public SelectClauseBuilder(Expression source, LambdaScope lambdaScope, IModel entityModel, Type extensionType, LambdaParameterNameFactory nameFactory,
                                   IResourceFactory resourceFactory, IResourceContextProvider resourceContextProvider)
            : base(lambdaScope)
        {
            ArgumentGuard.NotNull(source, nameof(source));
            ArgumentGuard.NotNull(entityModel, nameof(entityModel));
            ArgumentGuard.NotNull(extensionType, nameof(extensionType));
            ArgumentGuard.NotNull(nameFactory, nameof(nameFactory));
            ArgumentGuard.NotNull(resourceFactory, nameof(resourceFactory));
            ArgumentGuard.NotNull(resourceContextProvider, nameof(resourceContextProvider));

            _source                  = source;
            _entityModel             = entityModel;
            _extensionType           = extensionType;
            _nameFactory             = nameFactory;
            _resourceFactory         = resourceFactory;
            _resourceContextProvider = resourceContextProvider;
        }
        private Expression CreateAssignmentRightHandSideForLayer(QueryLayer layer, LambdaScope outerLambdaScope, MemberExpression propertyAccess,
                                                                 PropertyInfo selectorPropertyInfo, LambdaScopeFactory lambdaScopeFactory)
        {
            Type collectionElementType = TypeHelper.TryGetCollectionElementType(selectorPropertyInfo.PropertyType);
            Type bodyElementType       = collectionElementType ?? selectorPropertyInfo.PropertyType;

            if (collectionElementType != null)
            {
                return(CreateCollectionInitializer(outerLambdaScope, selectorPropertyInfo, bodyElementType, layer, lambdaScopeFactory));
            }

            if (layer.Projection == null || !layer.Projection.Any())
            {
                return(propertyAccess);
            }

            using var scope = lambdaScopeFactory.CreateScope(bodyElementType, propertyAccess);
            return(CreateLambdaBodyInitializer(layer.Projection, layer.ResourceContext, scope, true));
        }
예제 #18
0
        protected QueryClauseBuilder(LambdaScope lambdaScope)
        {
            ArgumentGuard.NotNull(lambdaScope, nameof(lambdaScope));

            LambdaScope = lambdaScope;
        }
 public OrderClauseBuilder(Expression source, LambdaScope lambdaScope, Type extensionType)
     : base(lambdaScope)
 {
     _source        = source ?? throw new ArgumentNullException(nameof(source));
     _extensionType = extensionType ?? throw new ArgumentNullException(nameof(extensionType));
 }
예제 #20
0
 protected QueryClauseBuilder(LambdaScope lambdaScope)
 {
     LambdaScope = lambdaScope ?? throw new ArgumentNullException(nameof(lambdaScope));
 }