Пример #1
0
        private void AddSchemaColumn(string outputColumn, string sourceColumn, NodeSchema schema, INodeSchema sourceSchema)
        {
            if (!sourceSchema.ContainsColumn(sourceColumn, out var normalized))
            {
                return;
            }

            var mapped = $"{Alias}.{outputColumn}";

            schema.Schema[mapped] = sourceSchema.Schema[normalized];

            if (normalized == sourceSchema.PrimaryKey)
            {
                schema.PrimaryKey = mapped;
            }

            if (!schema.Aliases.TryGetValue(outputColumn, out var aliases))
            {
                aliases = new List <string>();
                schema.Aliases[outputColumn] = aliases;
            }

            aliases.Add(mapped);

            var sorted = sourceSchema.SortOrder.Contains(sourceColumn, StringComparer.OrdinalIgnoreCase);

            if (sorted)
            {
                schema.SortOrder.Add(outputColumn);
            }
        }
Пример #2
0
        protected List <string> GetGroupingColumns(INodeSchema schema)
        {
            var groupByCols = GroupBy
                              .Select(col =>
            {
                var colName = col.GetColumnName();
                schema.ContainsColumn(colName, out colName);
                return(colName);
            })
                              .ToList();

            return(groupByCols);
        }
Пример #3
0
        public override void Visit(BooleanComparisonExpression node)
        {
            base.Visit(node);

            if (node.FirstExpression is ColumnReferenceExpression lhsCol &&
                node.SecondExpression is ColumnReferenceExpression rhsCol &&
                node.ComparisonType == BooleanComparisonType.Equals)
            {
                var lhsName = lhsCol.GetColumnName();
                var rhsName = rhsCol.GetColumnName();

                if (_lhs.ContainsColumn(lhsName, out _) && _rhs.ContainsColumn(rhsName, out _))
                {
                    LhsKey = lhsCol;
                    RhsKey = rhsCol;
                }
                else if (_lhs.ContainsColumn(rhsName, out _) && _rhs.ContainsColumn(lhsName, out _))
                {
                    LhsKey = rhsCol;
                    RhsKey = lhsCol;
                }

                JoinCondition = node;
                return;
            }

            if (AllowExpressions &&
                node.ComparisonType == BooleanComparisonType.Equals)
            {
                // Check each expression includes at least one column reference and relates entirely to one source
                var firstColumns  = node.FirstExpression.GetColumns().ToList();
                var secondColumns = node.SecondExpression.GetColumns().ToList();

                if (firstColumns.Count == 0 || secondColumns.Count == 0)
                {
                    return;
                }

                var firstIsLhs  = firstColumns.Any(c => _lhs.ContainsColumn(c, out _));
                var firstIsRhs  = firstColumns.Any(c => _rhs.ContainsColumn(c, out _));
                var secondIsLhs = secondColumns.Any(c => _lhs.ContainsColumn(c, out _));
                var secondIsRhs = secondColumns.Any(c => _rhs.ContainsColumn(c, out _));

                if (firstIsLhs && !firstIsRhs && !secondIsLhs && secondIsRhs)
                {
                    LhsExpression = node.FirstExpression;
                    RhsExpression = node.SecondExpression;
                }
                else if (!firstIsLhs && firstIsRhs && secondIsLhs && !secondIsRhs)
                {
                    LhsExpression = node.SecondExpression;
                    RhsExpression = node.FirstExpression;
                }
                else
                {
                    return;
                }

                LhsKey = LhsExpression as ColumnReferenceExpression;
                RhsKey = RhsExpression as ColumnReferenceExpression;
            }
        }
Пример #4
0
        /// <summary>
        /// Compiles methods to access the data required for the DML operation
        /// </summary>
        /// <param name="mappings">The mappings of attribute name to source column</param>
        /// <param name="schema">The schema of data source</param>
        /// <param name="attributes">The attributes in the target metadata</param>
        /// <param name="dateTimeKind">The time zone that datetime values are supplied in</param>
        /// <returns></returns>
        protected Dictionary <string, Func <Entity, object> > CompileColumnMappings(EntityMetadata metadata, IDictionary <string, string> mappings, INodeSchema schema, IDictionary <string, AttributeMetadata> attributes, DateTimeKind dateTimeKind)
        {
            var attributeAccessors = new Dictionary <string, Func <Entity, object> >();
            var entityParam        = Expression.Parameter(typeof(Entity));

            foreach (var mapping in mappings)
            {
                var sourceColumnName  = mapping.Value;
                var destAttributeName = mapping.Key;

                if (!schema.ContainsColumn(sourceColumnName, out sourceColumnName))
                {
                    throw new QueryExecutionException($"Missing source column {mapping.Value}")
                          {
                              Node = this
                          }
                }
                ;

                // We might be using a virtual ___type attribute that has a different name in the metadata. We can safely
                // ignore these attributes - the attribute names have already been validated in the ExecutionPlanBuilder
                if (!attributes.TryGetValue(destAttributeName, out var attr) || attr.AttributeOf != null)
                {
                    continue;
                }

                var sourceType  = schema.Schema[sourceColumnName];
                var destType    = attr.GetAttributeType();
                var destSqlType = SqlTypeConverter.NetToSqlType(destType);

                var expr         = (Expression)Expression.Property(entityParam, typeof(Entity).GetCustomAttribute <DefaultMemberAttribute>().MemberName, Expression.Constant(sourceColumnName));
                var originalExpr = expr;

                if (sourceType == typeof(object))
                {
                    // null literal
                    expr = Expression.Constant(null, destType);
                    expr = Expr.Box(expr);
                }
                else
                {
                    expr = SqlTypeConverter.Convert(expr, sourceType);
                    expr = SqlTypeConverter.Convert(expr, destSqlType);
                    var convertedExpr = SqlTypeConverter.Convert(expr, destType);

                    if (attr is LookupAttributeMetadata lookupAttr && lookupAttr.AttributeType != AttributeTypeCode.PartyList)
                    {
                        // Special case: intersect attributes can be simple guids
                        if (metadata.IsIntersect != true)
                        {
                            if (sourceType == typeof(SqlEntityReference))
                            {
                                expr          = SqlTypeConverter.Convert(originalExpr, sourceType);
                                convertedExpr = SqlTypeConverter.Convert(expr, typeof(EntityReference));
                            }
                            else
                            {
                                Expression targetExpr;

                                if (lookupAttr.Targets.Length == 1)
                                {
                                    targetExpr = Expression.Constant(lookupAttr.Targets[0]);
                                }
                                else
                                {
                                    var sourceTargetColumnName = mappings[destAttributeName + "type"];
                                    var sourceTargetType       = schema.Schema[sourceTargetColumnName];
                                    targetExpr = Expression.Property(entityParam, typeof(Entity).GetCustomAttribute <DefaultMemberAttribute>().MemberName, Expression.Constant(sourceTargetColumnName));
                                    targetExpr = SqlTypeConverter.Convert(targetExpr, sourceTargetType);
                                    targetExpr = SqlTypeConverter.Convert(targetExpr, typeof(SqlString));
                                    targetExpr = SqlTypeConverter.Convert(targetExpr, typeof(string));
                                }

                                convertedExpr = Expression.New(
                                    typeof(EntityReference).GetConstructor(new[] { typeof(string), typeof(Guid) }),
                                    targetExpr,
                                    Expression.Convert(convertedExpr, typeof(Guid))
                                    );
                            }

                            destType = typeof(EntityReference);
                        }
                    }
                    else if (attr is EnumAttributeMetadata && !(attr is MultiSelectPicklistAttributeMetadata))
                    {
                        convertedExpr = Expression.New(
                            typeof(OptionSetValue).GetConstructor(new[] { typeof(int) }),
                            Expression.Convert(convertedExpr, typeof(int))
                            );
                        destType = typeof(OptionSetValue);
                    }
                    else if (attr is MoneyAttributeMetadata)
                    {
                        convertedExpr = Expression.New(
                            typeof(Money).GetConstructor(new[] { typeof(decimal) }),
                            Expression.Convert(expr, typeof(decimal))
                            );
                        destType = typeof(Money);
                    }
                    else if (attr is DateTimeAttributeMetadata)
                    {
                        convertedExpr = Expression.Convert(
                            Expr.Call(() => DateTime.SpecifyKind(Expr.Arg <DateTime>(), Expr.Arg <DateTimeKind>()),
                                      expr,
                                      Expression.Constant(dateTimeKind)
                                      ),
                            typeof(DateTime?)
                            );
                    }

                    // Check for null on the value BEFORE converting from the SQL to BCL type to avoid e.g. SqlDateTime.Null being converted to 1900-01-01
                    expr = Expression.Condition(
                        SqlTypeConverter.NullCheck(expr),
                        Expression.Constant(null, destType),
                        convertedExpr);

                    if (expr.Type.IsValueType)
                    {
                        expr = SqlTypeConverter.Convert(expr, typeof(object));
                    }
                }

                attributeAccessors[destAttributeName] = Expression.Lambda <Func <Entity, object> >(expr, entityParam).Compile();
            }