예제 #1
0
        private void CreateRelationshipExpression(AssociationDescriptor assoc, Type type, Type memberType, Type propertyType)
        {
            MethodInfo method  = typeof(Builder).GetMethod(nameof(Builder.CreateRelationshipEnumerableExpression));
            MethodInfo generic = method.MakeGenericMethod(type, memberType, propertyType);

            generic.Invoke(this, new object[] { assoc });
        }
예제 #2
0
        public void CreateRelationshipExpression <T, U>(AssociationDescriptor assoc)
        {
            var t        = BuildJoinExpression <T, U>(assoc, typeof(T), typeof(U)) as Expression <Func <T, U, bool> >;
            var property = CreateExpression <T, U>(t.Parameters[0], assoc.MemberInfo.Name);

            AddRelationship(property, t);
        }
 private static void SetTableAlias(AssociationDescriptor association, SqlTableSource?table)
 {
     if (table != null)
     {
         var alias = association.GenerateAlias();
         if (!alias.IsNullOrEmpty())
         {
             table.Alias = alias;
         }
     }
 }
 public void ClearHandler(Object obj, EventArgs e)
 {
     _baseTrackingDevice = null;
     _associateTrackingDeviceButton.Enabled = true;
     _trackingDeviceLabel.Text = "";
     _itemsPrenotation.Clear();
     _itemPrenotationListView.Clear();
     _packets.Clear();
     _packetListView.Clear();
     _bundles.Clear();
     _bundleListView.Clear();
     _createButton.Enabled = false;
     _clearButton.Enabled  = false;
     _desc = null;
 }
예제 #5
0
            public AssociatedTableContext(ExpressionBuilder builder, TableContext parent, AssociationDescriptor association)
                : base(builder, parent.SelectQuery)
            {
                var type = association.MemberInfo.GetMemberType();
                var left = association.CanBeNull;

                if (typeof(IEnumerable).IsSameOrParentOf(type))
                {
                    var etypes = type.GetGenericArguments(typeof(IEnumerable <>));
                    type   = etypes != null && etypes.Length > 0 ? etypes[0] : type.GetListItemType();
                    IsList = true;
                }

                OriginalType     = type;
                ObjectType       = GetObjectType();
                EntityDescriptor = Builder.MappingSchema.GetEntityDescriptor(ObjectType);
                SqlTable         = new SqlTable(builder.MappingSchema, ObjectType);

                var psrc = parent.SelectQuery.From[parent.SqlTable];
                var join = left ? SqlTable.WeakLeftJoin() : IsList?SqlTable.InnerJoin() : SqlTable.WeakInnerJoin();

                Association           = association;
                ParentAssociation     = parent;
                ParentAssociationJoin = join.JoinedTable;

                psrc.Joins.Add(join.JoinedTable);

                for (var i = 0; i < association.ThisKey.Length; i++)
                {
                    SqlField field1;
                    SqlField field2;

                    if (!parent.SqlTable.Fields.TryGetValue(association.ThisKey[i], out field1))
                    {
                        throw new LinqException("Association key '{0}' not found for type '{1}.", association.ThisKey[i], parent.ObjectType);
                    }

                    if (!SqlTable.Fields.TryGetValue(association.OtherKey[i], out field2))
                    {
                        throw new LinqException("Association key '{0}' not found for type '{1}.", association.OtherKey[i], ObjectType);
                    }

                    join.Field(field1).Equal.Field(field2);
                }

                Init();
            }
 public void AddTrackingDevice(ITrackingDevice trackingDevice, AssociationDescriptor associationDescriptor)
 {
     #region Precondizioni
     if (trackingDevice == null)
     {
         throw new ArgumentNullException("tracking device null");
     }
     if (associationDescriptor == null)
     {
         throw new ArgumentNullException("association Descriptor null");
     }
     if (!PrenotationDate.Contains(associationDescriptor.DateRange))
     {
         throw new Exception("date range not valid");
     }
     #endregion
     _tdAssociations.Add(trackingDevice, associationDescriptor);
     OnPrenotatitionChangedHandler(this, new PrenotationEventArgs(this));
 }
예제 #7
0
        public static IBuildContext BuildAssociationSelectMany(ExpressionBuilder builder, BuildInfo buildInfo, TableBuilder.TableContext tableContext,
                                                               MemberInfo 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);
        }
        public void AddTrackingDeviceButtonHandler(Object obj, EventArgs e)
        {
            DateRange range = new DateRange(_fromDateTimePicker.Value, _toDateTimePicker.Value);

            using (StringDialog sd = new StringDialog("Nome da associare a prenotazione base: "))
            {
                if (sd.ShowDialog() == DialogResult.OK)
                {
                    string name = sd.Response;

                    if (name != null)
                    {
                        _desc = new AssociationDescriptor(range, name);
                    }
                }
                else
                {
                    return;
                }
            }
            if (_desc == null)
            {
                _desc = new AssociationDescriptor(range, "Base");
            }
            try
            {
                _baseTrackingDevice = _tdCoord.Next;
            }catch (Exception exception)
            {
                MessageBox.Show("Non è possibile recuperare un tracking device. Chiedi allo staff");
                _view.Close();
                return;
            }

            _trackingDeviceLabel.Text = _desc.InformationString + " -> " + _baseTrackingDevice.Id;
            _associateTrackingDeviceButton.Enabled = false;
            if (CanCreate())
            {
                _createButton.Enabled = true;
            }
            _clearButton.Enabled = true;
        }
예제 #9
0
        internal static Expression <Func <TParent, TChild, bool> > BuildJoinExpression <TParent, TChild>(
            AssociationDescriptor assoc, Type declaringType, Type memberEntityType)
        {
            var predicate = assoc.GetPredicate(declaringType, memberEntityType);

            var parentParam = predicate?.Parameters.FirstOrDefault() ?? Expression.Parameter(declaringType, "p");

            var childParam = predicate?.Parameters.Skip(1).FirstOrDefault() ??
                             Expression.Parameter(memberEntityType, "c");

            var previousExpr = BuildJoinClauseByForeignKey(assoc, predicate, parentParam, childParam);

            if (previousExpr is LambdaExpression lambda)
            {
                previousExpr = lambda.Body;
            }

            var expr = Expression.Lambda <Func <TParent, TChild, bool> >(previousExpr, parentParam, childParam);

            return(expr);
        }
예제 #10
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));
        }
예제 #11
0
        private static Expression BuildJoinClauseByForeignKey(
            AssociationDescriptor assoc,
            LambdaExpression predicate,
            ParameterExpression parentParam,
            ParameterExpression childParam)
        {
            Expression previousExpr = predicate == null ? null :
                                      SubstituteParameters(predicate, parentParam, childParam);

            if (previousExpr is LambdaExpression lambdaExpression)
            {
                previousExpr = lambdaExpression.Body;
            }

            for (int i = 0; i < assoc.ThisKey.Length; i++)
            {
                Expression childProperty  = Expression.Property(childParam, assoc.OtherKey[i]);
                Expression parentProperty = Expression.Property(parentParam, assoc.ThisKey[i]);

                if (childProperty.Type != parentProperty.Type)
                {
                    parentProperty = Expression.Convert(parentProperty, childProperty.Type);
                }

                var equals = Expression.Equal(parentProperty, childProperty);
                if (previousExpr == null)
                {
                    previousExpr = equals;
                }
                else
                {
                    previousExpr = Expression.AndAlso(previousExpr, equals);
                }
            }

            return(previousExpr);
        }
            public AssociatedTableContext(
                [JetBrains.Annotations.NotNull] ExpressionBuilder builder,
                [JetBrains.Annotations.NotNull] TableContext parent,
                [JetBrains.Annotations.NotNull] AssociationDescriptor association
                )
                : base(builder, parent.SelectQuery)
            {
                if (builder == null)
                {
                    throw new ArgumentNullException(nameof(builder));
                }
                if (parent == null)
                {
                    throw new ArgumentNullException(nameof(parent));
                }
                if (association == null)
                {
                    throw new ArgumentNullException(nameof(association));
                }

                var type = association.MemberInfo.GetMemberType();
                var left = association.CanBeNull;

                if (typeof(IEnumerable).IsSameOrParentOf(type))
                {
                    var eTypes = type.GetGenericArguments(typeof(IEnumerable <>));
                    type   = eTypes != null && eTypes.Length > 0 ? eTypes[0] : type.GetListItemType();
                    IsList = true;
                }

                OriginalType       = type;
                ObjectType         = GetObjectType();
                EntityDescriptor   = Builder.MappingSchema.GetEntityDescriptor(ObjectType);
                InheritanceMapping = EntityDescriptor.InheritanceMapping;
                SqlTable           = new SqlTable(builder.MappingSchema, ObjectType);

                Association       = association;
                ParentAssociation = parent;

                SqlJoinedTable join;

                var queryMethod = Association.GetQueryMethod(parent.ObjectType, ObjectType);

                if (queryMethod != null)
                {
                    var dcParam     = queryMethod.Parameters[1];
                    var resultParam = Expression.Parameter(ObjectType);

                    Expression dcConst = Expression.Constant(builder.DataContext);
                    if (dcParam.Type != typeof(IDataContext))
                    {
                        dcConst = Expression.Convert(dcConst, dcParam.Type);
                    }

                    var body = queryMethod.Body.Transform(e => e == dcParam ? dcConst : e);
                    body        = Expression.Convert(body, typeof(IEnumerable <>).MakeGenericType(ObjectType));
                    queryMethod = Expression.Lambda(body, queryMethod.Parameters[0]);

                    var selectManyMethodInfo = _selectManyMethodInfo.MakeGenericMethod(parent.ObjectType, ObjectType, ObjectType);
                    var resultLamba          = Expression.Lambda(resultParam, Expression.Parameter(parent.ObjectType), resultParam);
                    var selectManyMethod     = Expression.Call(null, selectManyMethodInfo, parent.Expression, queryMethod, resultLamba);
                    var ownerTableSource     = SelectQuery.From.Tables[0];

                    _innerContext = builder.BuildSequence(new BuildInfo(this, selectManyMethod, new SelectQuery())
                    {
                        IsAssociationBuilt = true
                    });

                    var associationQuery = _innerContext.SelectQuery;

                    if (associationQuery.Select.From.Tables.Count < 1)
                    {
                        throw new LinqToDBException("Invalid association query. It is not possible to inline query.");
                    }

                    var foundIndex = associationQuery.Select.From.Tables.FindIndex(t =>
                                                                                   t.Source is SqlTable sqlTable && QueryHelper.IsEqualTables(sqlTable, parent.SqlTable));

                    if (foundIndex < 0)
                    {
                        throw new LinqToDBException("Invalid association query. It is not possible to inline query. Can not find owner table.");
                    }

                    var sourceToReplace = associationQuery.Select.From.Tables[foundIndex];

                    if (left)
                    {
                        foreach (var joinedTable in sourceToReplace.Joins)
                        {
                            if (joinedTable.JoinType == JoinType.Inner)
                            {
                                joinedTable.JoinType = JoinType.Left;
                            }
                            else if (joinedTable.JoinType == JoinType.CrossApply)
                            {
                                joinedTable.JoinType = JoinType.OuterApply;
                            }

                            joinedTable.IsWeak = true;
                        }
                    }

                    ownerTableSource.Joins.AddRange(sourceToReplace.Joins);

                    // prepare fields mapping to replace fields that will be generated by association query
                    _replaceMap =
                        ((SqlTable)sourceToReplace.Source).Fields.Values.ToDictionary(f => (ISqlExpression)f,
                                                                                      f => parent.SqlTable.Fields[f.Name]);

                    ownerTableSource.Walk(false, e =>
                    {
                        if (_replaceMap.TryGetValue(e, out var newField))
                        {
                            return(newField);
                        }
                        return(e);
                    });

                    ParentAssociationJoin = sourceToReplace.Joins.FirstOrDefault();
                    join = ParentAssociationJoin;

                    // add rest of tables
                    SelectQuery.From.Tables.AddRange(associationQuery.Select.From.Tables.Where(t => t != sourceToReplace));
                }
                else
                {
                    var psrc = parent.SelectQuery.From[parent.SqlTable];
                    join = left ? SqlTable.WeakLeftJoin().JoinedTable : SqlTable.WeakInnerJoin().JoinedTable;

                    ParentAssociationJoin = join;

                    psrc.Joins.Add(join);

                    for (var i = 0; i < association.ThisKey.Length; i++)
                    {
                        if (!parent.SqlTable.Fields.TryGetValue(association.ThisKey[i], out var field1))
                        {
                            throw new LinqException("Association key '{0}' not found for type '{1}.", association.ThisKey[i], parent.ObjectType);
                        }

                        if (!SqlTable.Fields.TryGetValue(association.OtherKey[i], out var field2))
                        {
                            throw new LinqException("Association key '{0}' not found for type '{1}.", association.OtherKey[i], ObjectType);
                        }

                        //					join.Field(field1).Equal.Field(field2);

                        ISqlPredicate predicate = new SqlPredicate.ExprExpr(
                            field1, SqlPredicate.Operator.Equal, field2);

                        predicate = builder.Convert(parent, predicate);

                        join.Condition.Conditions.Add(new SqlCondition(false, predicate));
                    }

                    if (ObjectType != OriginalType)
                    {
                        var predicate = Builder.MakeIsPredicate(this, OriginalType);

                        if (predicate.GetType() != typeof(SqlPredicate.Expr))
                        {
                            join.Condition.Conditions.Add(new SqlCondition(false, predicate));
                        }
                    }

                    RegularConditionCount = join.Condition.Conditions.Count;
                    ExpressionPredicate   = Association.GetPredicate(parent.ObjectType, ObjectType);

                    if (ExpressionPredicate != null)
                    {
                        ExpressionPredicate = (LambdaExpression)Builder.ConvertExpressionTree(ExpressionPredicate);

                        var expr = Builder.ConvertExpression(ExpressionPredicate.Body.Unwrap());

                        Builder.BuildSearchCondition(
                            new ExpressionContext(parent.Parent, new IBuildContext[] { parent, this }, ExpressionPredicate),
                            expr,
                            join.Condition.Conditions,
                            false);
                    }
                }

                if (!association.AliasName.IsNullOrEmpty() && join != null)
                {
                    join.Table.Alias = association.AliasName;
                }
                else
                {
                    if (!Common.Configuration.Sql.AssociationAlias.IsNullOrEmpty() && join != null)
                    {
                        join.Table.Alias = string.Format(Common.Configuration.Sql.AssociationAlias,
                                                         association.MemberInfo.Name);
                    }
                }

                Init(false);
            }
            private void BuildAssociationCondition(ExpressionBuilder builder, TableContext parent, AssociationDescriptor association, SqlSearchCondition condition)
            {
                for (var i = 0; i < association.ThisKey.Length; i++)
                {
                    if (!parent.SqlTable.Fields.TryGetValue(association.ThisKey[i], out var field1))
                    {
                        throw new LinqException("Association key '{0}' not found for type '{1}.", association.ThisKey[i], parent.ObjectType);
                    }

                    if (!SqlTable.Fields.TryGetValue(association.OtherKey[i], out var field2))
                    {
                        throw new LinqException("Association key '{0}' not found for type '{1}.", association.OtherKey[i], ObjectType);
                    }

                    ISqlPredicate predicate = new SqlPredicate.ExprExpr(
                        field1, SqlPredicate.Operator.Equal, field2);

                    predicate = builder.Convert(parent, predicate);

                    condition.Conditions.Add(new SqlCondition(false, predicate));
                }

                if (ObjectType != OriginalType)
                {
                    var predicate = Builder.MakeIsPredicate(this, OriginalType);

                    if (predicate.GetType() != typeof(SqlPredicate.Expr))
                    {
                        condition.Conditions.Add(new SqlCondition(false, predicate));
                    }
                }

                RegularConditionCount = condition.Conditions.Count;
                ExpressionPredicate   = Association.GetPredicate(parent.ObjectType, ObjectType);

                if (ExpressionPredicate != null)
                {
                    ExpressionPredicate = (LambdaExpression)Builder.ConvertExpressionTree(ExpressionPredicate);

                    var expr = Builder.ConvertExpression(ExpressionPredicate.Body.Unwrap());

                    Builder.BuildSearchCondition(
                        new ExpressionContext(parent.Parent, new IBuildContext[] { parent, this }, ExpressionPredicate),
                        expr,
                        condition.Conditions,
                        false);
                }
            }
예제 #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(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);
        }
예제 #15
0
 public string[] GetThisKeys() => AssociationDescriptor.ParseKeys(ThisKey);
예제 #16
0
 public string[] GetOtherKeys() => AssociationDescriptor.ParseKeys(OtherKey);
            private void BuildSubQuery(ExpressionBuilder builder, TableContext parent, AssociationDescriptor association, bool left)
            {
                var queryMethod = Association.GetQueryMethod(parent.ObjectType, ObjectType);

                if (queryMethod != null)
                {
                    var subquery = GetAssociationQueryExpressionAsSubQuery(Expression.Constant(builder.DataContext), queryMethod);

                    // TODO: need to build without join here
                    _innerContext = builder.BuildSequence(
                        new BuildInfo(
                            new ExpressionContext(null, new[] { parent }, subquery),
                            subquery.Body,
                            new SelectQuery()
                    {
                        ParentSelect = SelectQuery.ParentSelect
                    }
                            )
                    {
                        IsAssociationBuilt = false
                    });

                    var associationQuery = _innerContext.SelectQuery;

                    if (associationQuery.Select.From.Tables.Count < 1)
                    {
                        throw new LinqToDBException("Invalid association query. It is not possible to inline query.");
                    }

                    SelectQuery = associationQuery;
                }
                else
                {
                    SelectQuery.From.Table(SqlTable);

                    BuildAssociationCondition(builder, parent, association, SelectQuery.Where.SearchCondition);
                }

                SetTableAlias(association, SelectQuery.From.Tables[0]);
            }
            public AssociatedTableContext(
                ExpressionBuilder builder,
                TableContext parent,
                AssociationDescriptor association,
                bool forceLeft,
                bool asSubquery
                )
                : base(builder, asSubquery ? new SelectQuery() { ParentSelect = parent.SelectQuery } : parent.SelectQuery)
            {
                if (builder == null)
                {
                    throw new ArgumentNullException(nameof(builder));
                }
                if (parent == null)
                {
                    throw new ArgumentNullException(nameof(parent));
                }
                if (association == null)
                {
                    throw new ArgumentNullException(nameof(association));
                }

                var type = association.MemberInfo.GetMemberType();
                var left = forceLeft || association.CanBeNull;

                if (typeof(IEnumerable).IsSameOrParentOf(type))
                {
                    var eTypes = type.GetGenericArguments(typeof(IEnumerable <>));
                    type   = eTypes != null && eTypes.Length > 0 ? eTypes[0] : type.GetListItemType();
                    IsList = true;
                }

                OriginalType       = type;
                ObjectType         = GetObjectType();
                EntityDescriptor   = Builder.MappingSchema.GetEntityDescriptor(ObjectType);
                InheritanceMapping = EntityDescriptor.InheritanceMapping;
                SqlTable           = new SqlTable(builder.MappingSchema, ObjectType);

                Association       = association;
                ParentAssociation = parent;
                IsSubQuery        = asSubquery;

                if (asSubquery)
                {
                    BuildSubQuery(builder, parent, association, left);
                    Init(false);
                    return;
                }

                SqlJoinedTable join;

                var queryMethod = Association.GetQueryMethod(parent.ObjectType, ObjectType);

                if (queryMethod != null)
                {
                    var selectManyMethod = GetAssociationQueryExpression(Expression.Constant(builder.DataContext),
                                                                         queryMethod.Parameters[0], parent.ObjectType, parent.Expression !, queryMethod);

                    var ownerTableSource = SelectQuery.From.Tables[0];

                    var buildInfo = new BuildInfo(this, selectManyMethod, new SelectQuery())
                    {
                        IsAssociationBuilt = true
                    };
                    _innerContext = builder.BuildSequence(buildInfo);

                    if (Association.CanBeNull)
                    {
                        _innerContext = new DefaultIfEmptyBuilder.DefaultIfEmptyContext(buildInfo.Parent, _innerContext, null);
                    }

                    var associationQuery = _innerContext.SelectQuery;

                    if (associationQuery.Select.From.Tables.Count < 1)
                    {
                        throw new LinqToDBException("Invalid association query. It is not possible to inline query.");
                    }

                    var foundIndex = associationQuery.Select.From.Tables.FindIndex(t =>
                                                                                   t.Source is SqlTable sqlTable && QueryHelper.IsEqualTables(sqlTable, parent.SqlTable));

                    // try to search table by object type
                    // TODO: review maybe there are another way to do that
                    if (foundIndex < 0)
                    {
                        foundIndex = associationQuery.Select.From.Tables.FindIndex(t =>
                                                                                   t.Source is SqlTable sqlTable && sqlTable.ObjectType == parent.SqlTable.ObjectType);
                    }

                    if (foundIndex < 0)
                    {
                        throw new LinqToDBException("Invalid association query. It is not possible to inline query. Can not find owner table.");
                    }

                    var sourceToReplace = associationQuery.Select.From.Tables[foundIndex];

                    if (left)
                    {
                        foreach (var joinedTable in sourceToReplace.Joins)
                        {
                            if (joinedTable.JoinType == JoinType.Inner)
                            {
                                joinedTable.JoinType = JoinType.Left;
                            }
                            else if (joinedTable.JoinType == JoinType.CrossApply)
                            {
                                joinedTable.JoinType = JoinType.OuterApply;
                            }

                            joinedTable.IsWeak = true;
                        }
                    }

                    ownerTableSource.Joins.AddRange(sourceToReplace.Joins);

                    // prepare fields mapping to replace fields that will be generated by association query
                    _replaceMap =
                        ((SqlTable)sourceToReplace.Source).Fields.Values.ToDictionary(f => (ISqlExpression)f,
                                                                                      f => parent.SqlTable.Fields[f.Name]);

                    ownerTableSource.Walk(new WalkOptions(), e =>
                    {
                        if (_replaceMap.TryGetValue(e, out var newField))
                        {
                            return(newField);
                        }
                        return(e);
                    });

                    ParentAssociationJoin = sourceToReplace.Joins.FirstOrDefault();
                    join = ParentAssociationJoin;

                    // add rest of tables
                    SelectQuery.From.Tables.AddRange(associationQuery.Select.From.Tables.Where(t => t != sourceToReplace));

                    //TODO: Change AssociatedTableContext base class
                    //SqlTable = null;
                }
                else
                {
                    var psrc = parent.SelectQuery.From[parent.SqlTable] !;
                    join = left ? SqlTable.WeakLeftJoin().JoinedTable : SqlTable.WeakInnerJoin().JoinedTable;

                    ParentAssociationJoin = join;

                    psrc.Joins.Add(join);
                    BuildAssociationCondition(builder, parent, association, join.Condition);
                }

                SetTableAlias(association, join?.Table);

                Init(false);
            }
        public CustomizableServizablePrenotation(ICustomer client, DateRange prenotationDate,
                                                 IEnumerable <IItemPrenotation> items, ITrackingDevice baseTrackingDevice,
                                                 AssociationDescriptor tdDesc, IEnumerable <IPacket> packets = null,
                                                 IEnumerable <IBundle> bundles = null)
        {
            #region Precondizioni
            if (prenotationDate == null)
            {
                throw new ArgumentNullException("range data null");
            }
            if (client == null)
            {
                throw new ArgumentNullException("client null");
            }
            if (items == null)
            {
                throw new ArgumentNullException("items null");
            }
            if (baseTrackingDevice == null)
            {
                throw new ArgumentNullException("baseTrackingDevice null");
            }
            if (tdDesc == null)
            {
                throw new ArgumentNullException("tdDesc null");
            }
            if (!tdDesc.DateRange.Equals(prenotationDate))
            {
                throw new InvalidOperationException("Il tracking device base deve essere +" +
                                                    "associato per tutta la prenotazione");
            }

            #endregion

            _client           = client;
            _prenotationDate  = prenotationDate;
            _bookedItems      = items.ToList();
            _packetsPurchases = new List <IPacketPurchase>();
            List <IPacket> packetList = new List <IPacket>();

            foreach (IPacket packet in packets ?? new IPacket[0])
            {
                if (!CanAdd(packet))
                {
                    throw new InvalidOperationException("packet not valid");
                }
                DateTime start = prenotationDate.StartDate > packet.Availability.StartDate ?
                                 prenotationDate.StartDate : packet.Availability.StartDate;

                _packetsPurchases.Add(new PacketPurchase(start, packet));
            }

            _bundles        = new HashSet <IBundle>();
            _tdAssociations = new Dictionary <ITrackingDevice, AssociationDescriptor>();
            AddTrackingDevice(baseTrackingDevice, tdDesc);

            foreach (IBundle bundle in bundles ?? new IBundle[0])
            {
                if (!CanAdd(bundle))
                {
                    throw new InvalidOperationException("bundle not valid");
                }
                _bundles.Add(bundle);
            }

            foreach (IItemPrenotation ip in _bookedItems)
            {
                if (!CanAdd(ip))
                {
                    throw new InvalidOperationException("item prenotation not valid");
                }
            }

            // Verifico che gli item comprano interamente la prenotazione
            // per ogni giorno ci deve essere almeno un item
            if (!IsIstantiable(_bookedItems))
            {
                throw new InvalidOperationException("gli item non comprono interamente la prenotazione");
            }
        }
 public CustomizableServizablePrenotation(ICustomer client, DateRange rangeData, IEnumerable <IItemPrenotation> items,
                                          ITrackingDevice baseTrackingDevice, AssociationDescriptor tdDesc, IEnumerable <IBundle> bundles)
     : this(client, rangeData, items, baseTrackingDevice, tdDesc, null, bundles)
 {
 }
            public AssociatedTableContext(
                [JetBrains.Annotations.NotNull] ExpressionBuilder builder,
                [JetBrains.Annotations.NotNull] TableContext parent,
                [JetBrains.Annotations.NotNull] AssociationDescriptor association
                )
                : base(builder, parent.SelectQuery)
            {
                if (builder == null)
                {
                    throw new ArgumentNullException(nameof(builder));
                }
                if (parent == null)
                {
                    throw new ArgumentNullException(nameof(parent));
                }
                if (association == null)
                {
                    throw new ArgumentNullException(nameof(association));
                }

                var type = association.MemberInfo.GetMemberType();
                var left = association.CanBeNull;

                if (typeof(IEnumerable).IsSameOrParentOf(type))
                {
                    var eTypes = type.GetGenericArguments(typeof(IEnumerable <>));
                    type   = eTypes != null && eTypes.Length > 0 ? eTypes[0] : type.GetListItemType();
                    IsList = true;
                }

                OriginalType       = type;
                ObjectType         = GetObjectType();
                EntityDescriptor   = Builder.MappingSchema.GetEntityDescriptor(ObjectType);
                InheritanceMapping = EntityDescriptor.InheritanceMapping;
                SqlTable           = new SqlTable(builder.MappingSchema, ObjectType);

                var psrc = parent.SelectQuery.From[parent.SqlTable];
                var join = left ? SqlTable.WeakLeftJoin() : SqlTable.WeakInnerJoin();

                if (!association.AliasName.IsNullOrEmpty())
                {
                    join.JoinedTable.Table.Alias = association.AliasName;
                }
                else
                {
                    if (!Common.Configuration.Sql.AssociationAlias.IsNullOrEmpty())
                    {
                        join.JoinedTable.Table.Alias = string.Format(Common.Configuration.Sql.AssociationAlias,
                                                                     association.MemberInfo.Name);
                    }
                }

                Association           = association;
                ParentAssociation     = parent;
                ParentAssociationJoin = join.JoinedTable;

                psrc.Joins.Add(join.JoinedTable);

                for (var i = 0; i < association.ThisKey.Length; i++)
                {
                    if (!parent.SqlTable.Fields.TryGetValue(association.ThisKey[i], out var field1))
                    {
                        throw new LinqException("Association key '{0}' not found for type '{1}.", association.ThisKey[i], parent.ObjectType);
                    }

                    if (!SqlTable.Fields.TryGetValue(association.OtherKey[i], out var field2))
                    {
                        throw new LinqException("Association key '{0}' not found for type '{1}.", association.OtherKey[i], ObjectType);
                    }

//					join.Field(field1).Equal.Field(field2);

                    ISqlPredicate predicate = new SqlPredicate.ExprExpr(
                        field1, SqlPredicate.Operator.Equal, field2);

                    predicate = builder.Convert(parent, predicate);

                    join.JoinedTable.Condition.Conditions.Add(new SqlCondition(false, predicate));
                }

                if (ObjectType != OriginalType)
                {
                    var predicate = Builder.MakeIsPredicate(this, OriginalType);

                    if (predicate.GetType() != typeof(SqlPredicate.Expr))
                    {
                        join.JoinedTable.Condition.Conditions.Add(new SqlCondition(false, predicate));
                    }
                }

                RegularConditionCount = join.JoinedTable.Condition.Conditions.Count;
                ExpressionPredicate   = Association.GetPredicate(parent.ObjectType, ObjectType);

                if (ExpressionPredicate != null)
                {
                    ExpressionPredicate = (LambdaExpression)Builder.ConvertExpressionTree(ExpressionPredicate);

                    var expr = Builder.ConvertExpression(ExpressionPredicate.Body.Unwrap());

                    Builder.BuildSearchCondition(
                        new ExpressionContext(parent.Parent, new IBuildContext[] { parent, this }, ExpressionPredicate),
                        expr,
                        join.JoinedTable.Condition.Conditions,
                        false);
                }

                Init(false);
            }
예제 #22
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) =>
예제 #23
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) =>