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 }); }
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; }
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)); }
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; }
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); }
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)); }
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); } }
// 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); }
public string[] GetThisKeys() => AssociationDescriptor.ParseKeys(ThisKey);
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); }
// 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) =>
// 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) =>