TransformInfo TransformExpression(IBuildContext context, Expression expr, bool enforceServerSide) { if (_skippedExpressions.Contains(expr)) { return(new TransformInfo(expr, true)); } if (expr.Find(IsNoneSqlMember) != null) { return(new TransformInfo(expr)); } switch (expr.NodeType) { case ExpressionType.Convert: case ExpressionType.ConvertChecked: { if (expr.Type == typeof(object)) { break; } var cex = (UnaryExpression)expr; _convertedExpressions.Add(cex.Operand, cex); var nex = BuildExpression(context, cex.Operand, enforceServerSide); if (nex.Type != cex.Type) { nex = cex.Update(nex); } var ret = new TransformInfo(nex, true); _convertedExpressions.Remove(cex.Operand); return(ret); } case ExpressionType.MemberAccess: { if (IsServerSideOnly(expr) || PreferServerSide(expr, enforceServerSide)) { return(new TransformInfo(BuildSql(context, expr))); } var ma = (MemberExpression)expr; var l = Expressions.ConvertMember(MappingSchema, ma.Expression == null ? null : ma.Expression.Type, ma.Member); if (l != null) { // In Grouping KeyContext we have to perform calculation on server side if (Contexts.Any(c => c is GroupByBuilder.KeyContext)) { return(new TransformInfo(BuildSql(context, expr))); } break; } if (ma.Member.IsNullableValueMember()) { break; } if (ma.Member.IsNullableHasValueMember()) { Expression e = Expression.NotEqual( ma.Expression, Expression.Constant(null, ma.Expression.Type)); return(new TransformInfo( BuildExpression( context, ma.Expression.Type.IsPrimitiveEx() ? Expression.Call( MemberHelper.MethodOf(() => Sql.AsSql(true)), e) : e, enforceServerSide), true)); } var ctx = GetContext(context, ma); if (ctx != null) { if (ma.Type.IsGenericTypeEx() && typeof(IEnumerable <>).IsSameOrParentOf(ma.Type)) { var res = ctx.IsExpression(ma, 0, RequestFor.Association); if (res.Result) { var table = (TableBuilder.AssociatedTableContext)res.Context; if (table.IsList) { var mexpr = GetMultipleQueryExpression(context, MappingSchema, ma, new HashSet <ParameterExpression>()); return(new TransformInfo(BuildExpression(context, mexpr, enforceServerSide))); } } } return(new TransformInfo(ctx.BuildExpression(ma, 0, enforceServerSide))); } var ex = ma.Expression; while (ex is MemberExpression) { ex = ((MemberExpression)ex).Expression; } if (ex is MethodCallExpression) { var ce = (MethodCallExpression)ex; if (IsSubQuery(context, ce)) { if (!IsMultipleQuery(ce)) { var info = GetSubQueryContext(context, ce); var par = Expression.Parameter(ex.Type); var bex = info.Context.BuildExpression(ma.Transform(e => e == ex ? par : e), 0, enforceServerSide); if (bex != null) { return(new TransformInfo(bex)); } } } } ex = ma.Expression; if (ex != null && ex.NodeType == ExpressionType.Constant) { // field = localVariable // var c = _expressionAccessors[ex]; return(new TransformInfo(Expression.MakeMemberAccess(Expression.Convert(c, ex.Type), ma.Member))); } break; } case ExpressionType.Parameter: { if (expr == ParametersParam) { break; } var ctx = GetContext(context, expr); if (ctx != null) { return(new TransformInfo(ctx.BuildExpression(expr, 0, enforceServerSide))); } break; } case ExpressionType.Constant: { if (expr.Type.IsConstantable()) { break; } if (_expressionAccessors.ContainsKey(expr)) { return(new TransformInfo(Expression.Convert(_expressionAccessors[expr], expr.Type))); } break; } case ExpressionType.Coalesce: if (expr.Type == typeof(string) && MappingSchema.GetDefaultValue(typeof(string)) != null) { return(new TransformInfo(BuildSql(context, expr))); } if (CanBeTranslatedToSql(context, ConvertExpression(expr), true)) { return(new TransformInfo(BuildSql(context, expr))); } break; case ExpressionType.Conditional: if (CanBeTranslatedToSql(context, ConvertExpression(expr), true)) { return(new TransformInfo(BuildSql(context, expr))); } break; case ExpressionType.Call: { var ce = (MethodCallExpression)expr; if (IsGroupJoinSource(context, ce)) { foreach (var arg in ce.Arguments.Skip(1)) { if (!_skippedExpressions.Contains(arg)) { _skippedExpressions.Add(arg); } } if (IsSubQuery(context, ce)) { if (ce.IsQueryable()) //if (!typeof(IEnumerable).IsSameOrParentOf(expr.Type) || expr.Type == typeof(string) || expr.Type.IsArray) { var ctx = GetContext(context, expr); if (ctx != null) { return(new TransformInfo(ctx.BuildExpression(expr, 0, enforceServerSide))); } } } break; } if (ce.IsAssociation(MappingSchema)) { var ctx = GetContext(context, ce); if (ctx == null) { throw new InvalidOperationException(); } return(new TransformInfo(ctx.BuildExpression(ce, 0, enforceServerSide))); } if ((_buildMultipleQueryExpressions == null || !_buildMultipleQueryExpressions.Contains(ce)) && IsSubQuery(context, ce)) { if (IsMultipleQuery(ce)) { return(new TransformInfo(BuildMultipleQuery(context, ce, enforceServerSide))); } return(new TransformInfo(GetSubQueryExpression(context, ce, enforceServerSide))); } if (IsServerSideOnly(expr) || PreferServerSide(expr, enforceServerSide) || ce.Method.IsSqlPropertyMethodEx()) { return(new TransformInfo(BuildSql(context, expr))); } } break; } if (EnforceServerSide(context)) { switch (expr.NodeType) { case ExpressionType.MemberInit: case ExpressionType.New: case ExpressionType.Convert: break; default: if (CanBeCompiled(expr)) { break; } return(new TransformInfo(BuildSql(context, expr))); } } return(new TransformInfo(expr)); }
public void RefreshContextsFromCache() { // Authentication factory is already registered in `OnImport()` AzureSession.Instance.TryGetComponent( PowerShellTokenCacheProvider.PowerShellTokenCacheProviderKey, out PowerShellTokenCacheProvider tokenCacheProvider); string authority = null; if (TryGetEnvironment(AzureSession.Instance.GetProperty(AzureSession.Property.Environment), out IAzureEnvironment sessionEnvironment)) { authority = $"{sessionEnvironment.ActiveDirectoryAuthority}organizations"; } var accounts = tokenCacheProvider.ListAccounts(authority); if (!accounts.Any()) { if (!Contexts.Any(c => c.Key != "Default" && c.Value.Account.Type == AzureAccount.AccountType.User)) { // If there are no accounts in the cache, but we never had any existing contexts, return return; } WriteWarningMessage($"No accounts found in the shared token cache; removing all user contexts."); var removedContext = false; foreach (var contextName in Contexts.Keys) { var context = Contexts[contextName]; if (context.Account.Type != AzureAccount.AccountType.User) { continue; } removedContext |= TryCacheRemoveContext(contextName); } // If no contexts were removed, return now to avoid writing to file later if (!removedContext) { return; } } else { var removedUsers = new HashSet <string>(); var updatedContext = false; foreach (var contextName in Contexts.Keys) { var context = Contexts[contextName]; if ((string.Equals(contextName, "Default") && context.Account == null) || context.Account.Type != AzureAccount.AccountType.User) { continue; } if (accounts.Any(a => string.Equals(a.Username, context.Account.Id, StringComparison.OrdinalIgnoreCase))) { continue; } if (!removedUsers.Contains(context.Account.Id)) { removedUsers.Add(context.Account.Id); WriteWarningMessage(string.Format(Resources.UserMissingFromSharedTokenCache, context.Account.Id)); } updatedContext |= TryCacheRemoveContext(contextName); } // Check to see if each account has at least one context foreach (var account in accounts) { if (Contexts.Values.Where(v => v.Account != null && v.Account.Type == AzureAccount.AccountType.User) .Any(v => string.Equals(v.Account.Id, account.Username, StringComparison.OrdinalIgnoreCase))) { continue; } WriteWarningMessage(string.Format(Resources.CreatingContextsWarning, account.Username)); var environment = sessionEnvironment ?? AzureEnvironment.PublicEnvironments .Where(env => env.Value.ActiveDirectoryAuthority.Contains(account.Environment)) .Select(env => env.Value) .FirstOrDefault(); var azureAccount = new AzureAccount() { Id = account.Username, Type = AzureAccount.AccountType.User }; List <IAccessToken> tokens = null; try { tokens = tokenCacheProvider.GetTenantTokensForAccount(account, environment, WriteWarningMessage); } catch (Exception e) { //In SSO scenario, if the account from token cache has multiple tenants, e.g. MSA account, MSAL randomly picks up //one tenant to ask for token, MSAL will throw exception if MSA home tenant is chosen. The exception is swallowed here as short term fix. WriteWarningMessage(string.Format(Resources.NoTokenFoundWarning, account.Username)); EnqueueDebugMessage(e.ToString()); continue; } foreach (var token in tokens) { var azureTenant = new AzureTenant() { Id = token.TenantId }; azureAccount.SetOrAppendProperty(AzureAccount.Property.Tenants, token.TenantId); var subscriptions = tokenCacheProvider.GetSubscriptionsFromTenantToken(account, environment, token, WriteWarningMessage); if (!subscriptions.Any()) { subscriptions.Add(null); } foreach (var subscription in subscriptions) { var context = new AzureContext(subscription, azureAccount, environment, azureTenant); if (!TryGetContextName(context, out string name)) { WriteWarningMessage(string.Format(Resources.NoContextNameForSubscription, subscription.Id)); continue; } if (!TrySetContext(name, context)) { WriteWarningMessage(string.Format(Resources.UnableToCreateContextForSubscription, subscription.Id)); } else { updatedContext = true; } } } } // If the context list was not updated, return now to avoid writing to file later if (!updatedContext) { return; } } Save(ProfilePath, false); }
TransformInfo TransformExpression(IBuildContext context, Expression expr, bool enforceServerSide, string?alias) { if (_skippedExpressions.Contains(expr)) { return(new TransformInfo(expr, true)); } alias ??= _optimizationContext.GetExpressionAlias(expr); switch (expr.NodeType) { case ExpressionType.Convert: case ExpressionType.ConvertChecked: { if (expr.Type == typeof(object)) { break; } var cex = (UnaryExpression)expr; _convertedExpressions.Add(cex.Operand, cex); var newOperand = BuildExpression(context, cex.Operand, enforceServerSide); if (newOperand.Type != cex.Type) { if (cex.Type.IsNullable() && newOperand is ConvertFromDataReaderExpression readerExpression) { newOperand = readerExpression.MakeNullable(); } newOperand = cex.Update(newOperand); } var ret = new TransformInfo(newOperand, true); RemoveConvertedExpression(cex.Operand); return(ret); } case ExpressionType.MemberAccess: { var ma = (MemberExpression)expr; if (IsServerSideOnly(ma) || PreferServerSide(ma, enforceServerSide) && !HasNoneSqlMember(ma)) { return(new TransformInfo(BuildSql(context, expr, alias))); } var l = Expressions.ConvertMember(MappingSchema, ma.Expression?.Type, ma.Member); if (l != null) { // In Grouping KeyContext we have to perform calculation on server side if (Contexts.Any(c => c is GroupByBuilder.KeyContext)) { return(new TransformInfo(BuildSql(context, expr, alias))); } break; } if (ma.Member.IsNullableValueMember()) { break; } var ctx = GetContext(context, ma); if (ctx != null) { var prevCount = ctx.SelectQuery.Select.Columns.Count; var expression = ctx.BuildExpression(ma, 0, enforceServerSide); if (expression.NodeType == ExpressionType.Extension && expression is DefaultValueExpression && ma.Expression?.NodeType == ExpressionType.Parameter) { var objExpression = BuildExpression(ctx, ma.Expression, enforceServerSide, alias); var varTempVar = objExpression.NodeType == ExpressionType.Parameter ? objExpression : BuildVariable(objExpression, ((ParameterExpression)ma.Expression).Name); var condition = Expression.Condition( Expression.Equal(varTempVar, new DefaultValueExpression(MappingSchema, ma.Expression.Type)), expression, Expression.MakeMemberAccess(varTempVar, ma.Member)); expression = condition; } else if (!alias.IsNullOrEmpty() && (ctx.SelectQuery.Select.Columns.Count - prevCount) == 1) { ctx.SelectQuery.Select.Columns[ctx.SelectQuery.Select.Columns.Count - 1].Alias = alias; } return(new TransformInfo(expression)); } var ex = ma.Expression; while (ex is MemberExpression memberExpression) { ex = memberExpression.Expression; } if (ex is MethodCallExpression ce) { if (IsSubQuery(context, ce)) { if (!IsMultipleQuery(ce, context.Builder.MappingSchema)) { var info = GetSubQueryContext(context, ce); if (alias != null) { info.Context.SetAlias(alias); } var par = Expression.Parameter(ex.Type); var bex = info.Context.BuildExpression(ma.Transform(e => e == ex ? par : e), 0, enforceServerSide); if (bex != null) { return(new TransformInfo(bex)); } } } } ex = ma.Expression; if (ex != null && ex.NodeType == ExpressionType.Constant) { // field = localVariable // if (!_expressionAccessors.TryGetValue(ex, out var c)) { return(new TransformInfo(ma)); } return(new TransformInfo(Expression.MakeMemberAccess(Expression.Convert(c, ex.Type), ma.Member))); } break; } case ExpressionType.Parameter: { if (expr == ParametersParam || expr == PreambleParam) { break; } var ctx = GetContext(context, expr); if (ctx != null) { var buildExpr = ctx.BuildExpression(expr, 0, enforceServerSide); if (buildExpr.Type != expr.Type) { buildExpr = Expression.Convert(buildExpr, expr.Type); } return(new TransformInfo(buildExpr)); } break; } case ExpressionType.Constant: { if (expr.Type.IsConstantable(true)) { break; } if ((_buildMultipleQueryExpressions == null || !_buildMultipleQueryExpressions.Contains(expr)) && IsSequence(new BuildInfo(context, expr, new SelectQuery()))) { return(new TransformInfo(BuildMultipleQuery(context, expr, enforceServerSide))); } if (_expressionAccessors.TryGetValue(expr, out var accessor)) { return(new TransformInfo(Expression.Convert(accessor, expr.Type))); } break; } case ExpressionType.Coalesce: if (expr.Type == typeof(string) && MappingSchema.GetDefaultValue(typeof(string)) != null) { return(new TransformInfo(BuildSql(context, expr, alias))); } if (CanBeTranslatedToSql(context, ConvertExpression(expr), true)) { return(new TransformInfo(BuildSql(context, expr, alias))); } break; case ExpressionType.Call: { var ce = (MethodCallExpression)expr; if (IsGroupJoinSource(context, ce)) { foreach (var arg in ce.Arguments.Skip(1)) { if (!_skippedExpressions.Contains(arg)) { _skippedExpressions.Add(arg); } } if (IsSubQuery(context, ce)) { if (ce.IsQueryable()) //if (!typeof(IEnumerable).IsSameOrParentOf(expr.Type) || expr.Type == typeof(string) || expr.Type.IsArray) { var ctx = GetContext(context, expr); if (ctx != null) { return(new TransformInfo(ctx.BuildExpression(expr, 0, enforceServerSide))); } } } break; } if (ce.IsAssociation(MappingSchema)) { var ctx = GetContext(context, ce); if (ctx == null) { throw new InvalidOperationException(); } return(new TransformInfo(ctx.BuildExpression(ce, 0, enforceServerSide))); } if ((_buildMultipleQueryExpressions == null || !_buildMultipleQueryExpressions.Contains(ce)) && IsSubQuery(context, ce)) { if (IsMultipleQuery(ce, MappingSchema)) { return(new TransformInfo(BuildMultipleQuery(context, ce, enforceServerSide))); } return(new TransformInfo(GetSubQueryExpression(context, ce, enforceServerSide, alias))); } if (IsServerSideOnly(expr) || PreferServerSide(expr, enforceServerSide) || ce.Method.IsSqlPropertyMethodEx()) { return(new TransformInfo(BuildSql(context, expr, alias))); } } break; case ExpressionType.New: { var ne = (NewExpression)expr; List <Expression>?arguments = null; for (var i = 0; i < ne.Arguments.Count; i++) { var argument = ne.Arguments[i]; var memberAlias = ne.Members?[i].Name; var newArgument = ConvertAssignmentArgument(context, argument, ne.Members?[i], enforceServerSide, memberAlias); if (newArgument != argument) { if (arguments == null) { arguments = ne.Arguments.Take(i).ToList(); } } arguments?.Add(newArgument); } if (arguments != null) { ne = ne.Update(arguments); } return(new TransformInfo(ne, true)); } case ExpressionType.MemberInit: { var mi = (MemberInitExpression)expr; var newPart = (NewExpression)BuildExpression(context, mi.NewExpression, enforceServerSide); List <MemberBinding>?bindings = null; for (var i = 0; i < mi.Bindings.Count; i++) { var binding = mi.Bindings[i]; var newBinding = binding; if (binding is MemberAssignment assignment) { var argument = ConvertAssignmentArgument(context, assignment.Expression, assignment.Member, enforceServerSide, assignment.Member.Name); if (argument != assignment.Expression) { newBinding = Expression.Bind(assignment.Member, argument); } } if (newBinding != binding) { if (bindings == null) { bindings = mi.Bindings.Take(i).ToList(); } } bindings?.Add(newBinding); } if (mi.NewExpression != newPart || bindings != null) { mi = mi.Update(newPart, bindings ?? mi.Bindings.AsEnumerable()); } return(new TransformInfo(mi, true)); } } if (enforceServerSide || EnforceServerSide(context)) { switch (expr.NodeType) { case ExpressionType.MemberInit: case ExpressionType.Convert: break; default: if (!enforceServerSide && CanBeCompiled(expr)) { break; } return(new TransformInfo(BuildSql(context, expr, alias))); } } return(new TransformInfo(expr)); }