Пример #1
0
        private bool ShouldSkipProperty(AccessorMember member, OperationContext operationContext)
        {
            var name = member.Name;

            if (name == nameof(ITableEntity.PartitionKey) ||
                name == nameof(ITableEntity.RowKey) ||
                name == nameof(ITableEntity.Timestamp) ||
                name == nameof(ITableEntity.ETag))
            {
                return(true);
            }

            if (!member.CanRead || !member.CanWrite)
            {
                _logger?.LogInformation(
                    "Omitting property '{0}' from serialization/de-serialization because the property's getter/setter are not public.",
                    member.Name);

                return(true);
            }

            if (member.HasAttribute <IgnorePropertyAttribute>())
            {
                _logger?.LogInformation(
                    FormatLine(operationContext,
                               $"Omitting property '{0}' from serialization/de-serialization because {nameof(IgnorePropertyAttribute)} has been set on that property.",
                               member.Name));

                return(true);
            }

            return(false);
        }
 private static bool IsValueType(AccessorMember x)
 {
     if (IsValueCollection(x))
     {
         return(true); // value collection
     }
     return(!x.Type.ImplementsGeneric(typeof(IEnumerable <>)));
 }
Пример #3
0
        private static string GetClusterName(AccessorMember member)
        {
            var name = member.TryGetAttribute(out DisplayNameAttribute display)
                                ? display.DisplayName ?? member.Name
                                : member.Name;

            return(name);
        }
Пример #4
0
        // ASP.NET Core MVC conventionally removes "Async" from the end of class methods
        private string ResolveActionName(AccessorMember method)
        {
            const string suffix = "Async";

            return(_options.Value.SuppressAsyncSuffixInActionNames &&
                   method.Name.EndsWith(suffix, StringComparison.Ordinal)
                                ? method.Name.Substring(0, method.Name.Length - suffix.Length)
                                : method.Name);
        }
        public bool IsSaved(AccessorMember member)
        {
            if (!member.TryGetAttribute(out DatabaseGeneratedAttribute attribute))
            {
                return(true);
            }

            return(attribute.DatabaseGeneratedOption switch
            {
                DatabaseGeneratedOption.None => true,
                DatabaseGeneratedOption.Identity => false,
                DatabaseGeneratedOption.Computed => false,
                _ => throw new ArgumentOutOfRangeException()
            });
Пример #6
0
        public static IBuildContext BuildAssociationSelectMany(ExpressionBuilder builder, BuildInfo buildInfo, TableBuilder.TableContext tableContext,
                                                               AccessorMember onMember, AssociationDescriptor descriptor, ref bool isOuter)
        {
            var elementType = descriptor.GetElementType(builder.MappingSchema);

            var queryMethod = CreateAssociationQueryLambda(
                builder, onMember, descriptor, tableContext.OriginalType, tableContext.ObjectType, elementType,
                false, isOuter, tableContext.LoadWith, out isOuter);

            var parentRef = new ContextRefExpression(queryMethod.Parameters[0].Type, tableContext);
            var body      = queryMethod.GetBody(parentRef);

            IBuildContext context;

            context = builder.BuildSequence(new BuildInfo(buildInfo, body));
            context.SelectQuery.From.Tables[0].Alias = descriptor.GenerateAlias();

            return(context);
        }
Пример #7
0
        private static string GetHttpTemplate(DynamicHttpMethodAttribute httpMethod, AccessorMember member)
        {
            if (member.DeclaringType != null)
            {
                if (member.DeclaringType.TryGetAttribute <RouteAttribute>(true, out var routeAttribute))
                {
                    var baseTemplate = routeAttribute.Template;

                    return(!string.IsNullOrWhiteSpace(httpMethod.Template)
                                                ? $"{baseTemplate}/{httpMethod.Template}"
                                                : baseTemplate);
                }
            }

            if (httpMethod.Template == string.Empty)
            {
                return(string.Empty);
            }

            return(!string.IsNullOrWhiteSpace(httpMethod.Template) ? httpMethod.Template : default);
Пример #8
0
        public PropertyAccessor(ITypeReadAccessor reads, ITypeWriteAccessor writes, Type type, string name)
        {
            Type = type;
            Name = name;

            _reads  = reads;
            _writes = writes;

            var members = AccessorMembers.Create(type);

            Info = members.PropertyInfo.SingleOrDefault(m => m.Name == name);

            var member = members.SingleOrDefault(p => p.Name == name);

            if (member == null)
            {
                return;
            }
            _member = member;
        }
Пример #9
0
        public static IBuildContext BuildAssociationInline(ExpressionBuilder builder, BuildInfo buildInfo, TableBuilder.TableContext tableContext,
                                                           AccessorMember onMember, AssociationDescriptor descriptor, bool inline, ref bool isOuter)
        {
            var elementType     = descriptor.GetElementType(builder.MappingSchema);
            var parentExactType = descriptor.GetParentElementType();

            var queryMethod = CreateAssociationQueryLambda(
                builder, onMember, descriptor, tableContext.OriginalType, parentExactType, elementType,
                inline, isOuter, tableContext.LoadWith, out isOuter);

            var parentRef = new ContextRefExpression(queryMethod.Parameters[0].Type, tableContext);
            var body      = queryMethod.GetBody(parentRef);

            var context = builder.BuildSequence(new BuildInfo(tableContext, body, new SelectQuery()));

            var tableSource = tableContext.SelectQuery.From.Tables.First();
            var join        = new SqlFromClause.Join(isOuter ? JoinType.OuterApply : JoinType.CrossApply, context.SelectQuery,
                                                     descriptor.GenerateAlias(), true, null);

            tableSource.Joins.Add(join.JoinedTable);

            return(new AssociationContext(builder, descriptor, tableContext, context, join.JoinedTable));
        }
Пример #10
0
        // Returns
        // (ParentType p) => dc.GetTable<ObjectType>().Where(...)
        // (ParentType p) => dc.GetTable<ObjectType>().Where(...).DefaultIfEmpty
        public static LambdaExpression CreateAssociationQueryLambda(ExpressionBuilder builder, AccessorMember onMember, AssociationDescriptor association,
                                                                    Type parentOriginalType,
                                                                    Type parentType,
                                                                    Type objectType, bool inline, bool enforceDefault,
                                                                    List <LoadWithInfo[]>?loadWith, out bool isLeft)
        {
            var dataContextConstant = Expression.Constant(builder.DataContext, builder.DataContext.GetType());

            // We are trying to keep fast cache hit behaviour, so cache check should be added only if needed
            //
            bool shouldAddCacheCheck = false;

            bool cacheCheckAdded = false;

            LambdaExpression?definedQueryMethod = null;

            if (association.HasQueryMethod())
            {
                // here we tell for Expression Comparer to compare optimized Association expressions
                //
                definedQueryMethod = (LambdaExpression)builder.AddQueryableMemberAccessors(onMember, builder.DataContext, (mi, dc) =>
                {
                    var queryLambda         = association.GetQueryMethod(parentType, objectType) ?? throw new InvalidOperationException();
                    var optimizationContext = new ExpressionTreeOptimizationContext(dc);
                    var optimizedExpr       = optimizationContext.ExposeExpression(queryLambda);
                    optimizedExpr           = optimizationContext.ExpandQueryableMethods(optimizedExpr);
                    return(optimizedExpr);
                });

                cacheCheckAdded = true;

                var parameterMatch = new Dictionary <ParameterExpression, Expression>();
                if (onMember.Arguments == null)
                {
                    if (definedQueryMethod.Parameters.Count > 1 && typeof(IDataContext).IsSameOrParentOf(definedQueryMethod.Parameters[1].Type))
                    {
                        parameterMatch.Add(definedQueryMethod.Parameters[1], dataContextConstant);
                    }
                }
                else
                {
                    var definedCount   = definedQueryMethod.Parameters.Count;
                    var argumentsCount = onMember.Arguments.Count;
                    var diff           = definedCount - argumentsCount;
                    for (int i = definedCount - 1; i >= diff; i--)
                    {
                        parameterMatch.Add(definedQueryMethod.Parameters[i], onMember.Arguments[i - diff]);
                    }
                }

                var body = definedQueryMethod.Body.Transform(parameterMatch, static (parameterMatch, e) =>
Пример #11
0
        // Returns
        // (ParentType p) => dc.GetTable<ObjectType>().Where(...)
        // (ParentType p) => dc.GetTable<ObjectType>().Where(...).DefaultIfEmpty
        public static LambdaExpression CreateAssociationQueryLambda(ExpressionBuilder builder, AccessorMember onMember, AssociationDescriptor association,
                                                                    Type parentOriginalType,
                                                                    Type parentType,
                                                                    Type objectType, bool inline, bool enforceDefault,
                                                                    List <LoadWithInfo[]>?loadWith, out bool isLeft)
        {
            var dataContextConstant = Expression.Constant(builder.DataContext, builder.DataContext.GetType());

            // We are trying to keep fast cache hit behaviour, so cache check should be added only if needed
            //
            bool shouldAddCacheCheck = false;

            bool cacheCheckAdded = false;

            LambdaExpression?definedQueryMethod = null;

            if (association.HasQueryMethod())
            {
                // here we tell for Expression Comparer to compare optimized Association expressions
                //
                definedQueryMethod = (LambdaExpression)builder.AddQueryableMemberAccessors(onMember, builder.DataContext, (mi, dc) =>
                {
                    var queryLambda         = association.GetQueryMethod(parentType, objectType) ?? throw new InvalidOperationException();
                    var optimizationContext = new ExpressionTreeOptimizationContext(dc);
                    var optimizedExpr       = optimizationContext.ExposeExpression(queryLambda);
                    optimizedExpr           = optimizationContext.ExpandQueryableMethods(optimizedExpr);
                    optimizedExpr           = optimizedExpr.OptimizeExpression() !;
                    return(optimizedExpr);
                });

                cacheCheckAdded = true;

                var parameterMatch = new Dictionary <ParameterExpression, Expression>();
                if (onMember.Arguments == null)
                {
                    if (definedQueryMethod.Parameters.Count > 1 && typeof(IDataContext).IsSameOrParentOf(definedQueryMethod.Parameters[1].Type))
                    {
                        parameterMatch.Add(definedQueryMethod.Parameters[1], dataContextConstant);
                    }
                }
                else
                {
                    var definedCount   = definedQueryMethod.Parameters.Count;
                    var argumentsCount = onMember.Arguments.Count;
                    var diff           = definedCount - argumentsCount;
                    for (int i = definedCount - 1; i >= diff; i--)
                    {
                        parameterMatch.Add(definedQueryMethod.Parameters[i], onMember.Arguments[i - diff]);
                    }
                }

                var body = definedQueryMethod.Body.Transform(e =>
                {
                    if (e.NodeType == ExpressionType.Parameter &&
                        parameterMatch.TryGetValue((ParameterExpression)e, out var newExpression))
                    {
                        return(newExpression);
                    }

                    return(e);
                });

                definedQueryMethod = Expression.Lambda(body, definedQueryMethod.Parameters[0]);
            }

            var shouldAddDefaultIfEmpty = enforceDefault;

            if (definedQueryMethod == null)
            {
                var parentParam = Expression.Parameter(parentType, "parent");
                var childParam  = Expression.Parameter(objectType, association.AliasName);

                var parentAccessor = TypeAccessor.GetAccessor(parentType);
                var childAccessor  = TypeAccessor.GetAccessor(objectType);

                Expression?predicate = null;
                for (var i = 0; i < association.ThisKey.Length; i++)
                {
                    var parentName   = association.ThisKey[i];
                    var parentMember = parentAccessor.Members.Find(m => m.MemberInfo.Name == parentName);

                    if (parentMember == null)
                    {
                        throw new LinqException("Association key '{0}' not found for type '{1}.", parentName,
                                                parentType);
                    }

                    var childName   = association.OtherKey[i];
                    var childMember = childAccessor.Members.Find(m => m.MemberInfo.Name == childName);

                    if (childMember == null)
                    {
                        throw new LinqException("Association key '{0}' not found for type '{1}.", childName,
                                                objectType);
                    }

                    var current = ExpressionBuilder.Equal(builder.MappingSchema,
                                                          Expression.MakeMemberAccess(parentParam, parentMember.MemberInfo),
                                                          Expression.MakeMemberAccess(childParam, childMember.MemberInfo));

                    predicate = predicate == null ? current : Expression.AndAlso(predicate, current);
                }

                var expressionPredicate = association.GetPredicate(parentType, objectType);

                if (expressionPredicate != null)
                {
                    shouldAddDefaultIfEmpty = true;
                    shouldAddCacheCheck     = true;

                    var replacedBody = expressionPredicate.GetBody(parentParam, childParam);

                    predicate = predicate == null ? replacedBody : Expression.AndAlso(predicate, replacedBody);
                }

                if (predicate == null)
                {
                    throw new LinqException("Can not generate Association predicate");
                }

                if (inline && !shouldAddDefaultIfEmpty)
                {
                    var ed = builder.MappingSchema.GetEntityDescriptor(objectType);
                    if (ed.QueryFilterFunc != null)
                    {
                        shouldAddDefaultIfEmpty = true;
                        shouldAddCacheCheck     = true;
                    }
                }

                var queryParam = Expression.Call(Methods.LinqToDB.GetTable.MakeGenericMethod(objectType), dataContextConstant);

                var        filterLambda = Expression.Lambda(predicate, childParam);
                Expression body         = Expression.Call(Methods.Queryable.Where.MakeGenericMethod(objectType), queryParam,
                                                          filterLambda);

                definedQueryMethod = Expression.Lambda(body, parentParam);
            }
            else
            {
                shouldAddDefaultIfEmpty = true;
                var bodyExpression = definedQueryMethod.Body.Unwrap();
                if (bodyExpression.NodeType == ExpressionType.Call)
                {
                    var mc = (MethodCallExpression)bodyExpression;
                    if (mc.IsSameGenericMethod(Methods.Queryable.DefaultIfEmpty, Methods.Queryable.DefaultIfEmptyValue))
                    {
                        shouldAddDefaultIfEmpty = false;
                    }
                }
            }

            if (!cacheCheckAdded && shouldAddCacheCheck)
            {
                // here we tell for Expression Comparer to compare optimized Association expressions
                //
                var closureExpr = definedQueryMethod;
                definedQueryMethod = (LambdaExpression)builder.AddQueryableMemberAccessors(onMember, builder.DataContext, (mi, dc) =>
                {
                    var optimizationContext = new ExpressionTreeOptimizationContext(dc);
                    var optimizedExpr       = optimizationContext.ExposeExpression(closureExpr);
                    optimizedExpr           = optimizationContext.ExpandQueryableMethods(optimizedExpr);
                    optimizedExpr           = optimizedExpr.OptimizeExpression() !;
                    return(optimizedExpr);
                });
            }

            if (loadWith != null)
            {
                var associationLoadWith = GetLoadWith(loadWith)?
                                          .FirstOrDefault(li => li.Info.MemberInfo == association.MemberInfo);

                if (associationLoadWith != null &&
                    (associationLoadWith.Info.MemberFilter != null || associationLoadWith.Info.FilterFunc != null))
                {
                    var body = definedQueryMethod.Body.Unwrap();

                    var memberFilter = associationLoadWith.Info.MemberFilter;
                    if (memberFilter != null)
                    {
                        var elementType = EagerLoading.GetEnumerableElementType(memberFilter.Parameters[0].Type,
                                                                                builder.MappingSchema);
                        var filtered   = Expression.Convert(body, typeof(IEnumerable <>).MakeGenericType(elementType));
                        var filterBody = memberFilter.GetBody(filtered);
                        body = Expression.Call(
                            Methods.Enumerable.AsQueryable.MakeGenericMethod(objectType), filterBody);
                    }

                    var loadWithFunc = associationLoadWith.Info.FilterFunc;

                    if (loadWithFunc != null)
                    {
                        loadWithFunc = loadWithFunc.Unwrap();
                        if (loadWithFunc is LambdaExpression lambda)
                        {
                            body = lambda.GetBody(body);
                        }
                        else
                        {
                            var filterDelegate = loadWithFunc.EvaluateExpression <Delegate>() ??
                                                 throw new LinqException("Cannot convert filter function '{loadWithFunc}' to Delegate.");

                            var arumentType = filterDelegate.GetType().GetGenericArguments()[0].GetGenericArguments()[0];
                            // check for fake argument q => q
                            if (arumentType.IsSameOrParentOf(objectType))
                            {
                                var query    = ExpressionQueryImpl.CreateQuery(objectType, builder.DataContext, body);
                                var filtered = (IQueryable)filterDelegate.DynamicInvoke(query) !;
                                body = filtered.Expression;
                            }
                        }
                    }

                    definedQueryMethod = Expression.Lambda(body, definedQueryMethod.Parameters);
                }

                if (associationLoadWith?.NextLoadWith != null && associationLoadWith.NextLoadWith.Count > 0)
                {
                    definedQueryMethod = (LambdaExpression)EnrichTablesWithLoadWith(builder.DataContext, definedQueryMethod, objectType,
                                                                                    associationLoadWith.NextLoadWith, builder.MappingSchema);
                }
            }

            if (parentOriginalType != parentType)
            {
                // add discriminator filter
                var ed = builder.MappingSchema.GetEntityDescriptor(parentOriginalType);
                foreach (var inheritanceMapping in ed.InheritanceMapping)
                {
                    if (inheritanceMapping.Type == parentType)
                    {
                        var objParam     = Expression.Parameter(objectType, "o");
                        var filterLambda = Expression.Lambda(ExpressionBuilder.Equal(builder.MappingSchema,
                                                                                     Expression.MakeMemberAccess(definedQueryMethod.Parameters[0], inheritanceMapping.Discriminator.MemberInfo),
                                                                                     Expression.Constant(inheritanceMapping.Code)), objParam);

                        var body = definedQueryMethod.Body.Unwrap();
                        body = Expression.Call(Methods.Queryable.Where.MakeGenericMethod(objectType),
                                               body, filterLambda);
                        definedQueryMethod = Expression.Lambda(body, definedQueryMethod.Parameters);

                        shouldAddDefaultIfEmpty = true;
                        break;
                    }
                }
            }

            if (inline && shouldAddDefaultIfEmpty)
            {
                var body = definedQueryMethod.Body.Unwrap();
                body = Expression.Call(Methods.Queryable.DefaultIfEmpty.MakeGenericMethod(objectType), body);
                definedQueryMethod = Expression.Lambda(body, definedQueryMethod.Parameters);
                isLeft             = true;
            }
            else
            {
                isLeft = false;
            }

            definedQueryMethod = (LambdaExpression)builder.ConvertExpressionTree(definedQueryMethod);
            definedQueryMethod = (LambdaExpression)builder.ConvertExpression(definedQueryMethod);
            definedQueryMethod = (LambdaExpression)definedQueryMethod.OptimizeExpression() !;

            return(definedQueryMethod);
        }
Пример #12
0
        public bool IsMatch(string template, PathString action, HttpContext httpContext, AccessorMember method, out RouteValueDictionary values)
        {
            if (template == null)
            {
                values = default;
                return(string.IsNullOrWhiteSpace(action));
            }

            if (template.Equals(action, StringComparison.OrdinalIgnoreCase))
            {
                values = default;
                return(true);
            }

            if (!Templates.TryGetValue(template, out var parsed))
            {
                Templates.Add(template, parsed = TemplateParser.Parse(template));
            }

            if (!Defaults.TryGetValue(template, out var defaults))
            {
                Defaults.Add(template, defaults = GetDefaultParameters(parsed));
            }

            if (!Matchers.TryGetValue(template, out var matcher))
            {
                Matchers.Add(template, matcher = new TemplateMatcher(parsed, defaults));
            }

            values = new RouteValueDictionary();

            if (!matcher.TryMatch(action, values))
            {
                return(false);
            }

            var constraints = method.Attributes.OfType <IActionConstraint>().OrderBy(x => x.Order).AsList();

            if (constraints.Count > 0)
            {
                var context = new ActionConstraintContext {
                    RouteContext = new RouteContext(httpContext)
                };
                foreach (var constraint in constraints)
                {
                    if (!constraint.Accept(context))
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
        private void IndexMember(IDbConnection db, IDbTransaction t, int revision, AccessorMember member, bool unique)
        {
            var sql = SqliteBuilder.CreateIndexSql(GetResourceName(), member.Name, revision, unique);

            db.Execute(sql, transaction: t);
        }
Пример #14
0
        // Returns
        // (ParentType p) => dc.GetTable<ObjectType>().Where(...)
        // (ParentType p) => dc.GetTable<ObjectType>().Where(...).DefaultIfEmpty
        public static LambdaExpression CreateAssociationQueryLambda(ExpressionBuilder builder, AccessorMember onMember, AssociationDescriptor association,
                                                                    Type parentOriginalType,
                                                                    Type parentType,
                                                                    Type objectType, bool inline, bool enforceDefault,
                                                                    List <LoadWithInfo[]>?loadWith, out bool isLeft)
        {
            var dataContextConstant = Expression.Constant(builder.DataContext, builder.DataContext.GetType());

            // We are trying to keep fast cache hit behaviour, so cache check should be added only if needed
            //
            bool shouldAddCacheCheck = false;

            bool cacheCheckAdded = false;

            LambdaExpression?definedQueryMethod = null;

            if (association.HasQueryMethod())
            {
                // here we tell for Expression Comparer to compare optimized Association expressions
                //
                definedQueryMethod = (LambdaExpression)builder.AddQueryableMemberAccessors((association, parentType, objectType), onMember, builder.DataContext, static (context, mi, dc) =>
Пример #15
0
 private static bool IsNumber(AccessorMember member)
 {
     return(member.Type == typeof(int));
 }
 public bool IsIgnored(AccessorMember member)
 {
     return(member.HasAttribute <NotMappedAttribute>());
 }
Пример #17
0
 private static string GetClusterColor(AccessorMember member)
 {
     return(member.TryGetAttribute(out ColorAttribute color) ? color.Color.ToRgbaHexString() : "blue");
 }
        private static object ResolveValue(object @object, IEnumerable <IFieldTransform> transforms, IReadAccessor accessor, AccessorMember v)
        {
            foreach (var field in transforms)
            {
                if (field.TryTransform(accessor, @object, v, out var transformed))
                {
                    return(transformed);
                }
            }

            accessor.TryGetValue(@object, v.Name, out var untransformed);
            return(untransformed);
        }
 private static bool IsSaved(IDataInfoProvider provider, AccessorMember member) => provider == null || provider.IsSaved(member);
 private static bool IsChildResource(AccessorMember x)
 {
     // other resources
     return(typeof(IResource).IsAssignableFrom(x.Type));
 }
 private static bool IsValueCollection(AccessorMember x)
 {
     return(x.Type == typeof(byte[]) || x.Type == typeof(string));
 }