public virtual SqlExpression Translate([NotNull] Expression expression) { Check.NotNull(expression, nameof(expression)); var result = Visit(expression); if (result is SqlExpression translation) { if (translation is SqlUnaryExpression sqlUnaryExpression && sqlUnaryExpression.OperatorType == ExpressionType.Convert && sqlUnaryExpression.Type == typeof(object)) { translation = sqlUnaryExpression.Operand; } translation = _sqlExpressionFactory.ApplyDefaultTypeMapping(translation); if ((translation is SqlConstantExpression || translation is SqlParameterExpression) && translation.TypeMapping == null) { // Non-mappable constant/parameter return(null); } _sqlTypeMappingVerifyingExpressionVisitor.Visit(translation); return(translation); } return(null); }
public virtual SqlExpression Translate( SqlExpression instance, MemberInfo member, System.Type returnType) { var declaringType = member.DeclaringType; if (declaringType == typeof(DateTime)) { var memberName = member.Name; if (s_datePartMapping.TryGetValue(memberName, out var datePart)) { var extract = _sqlExpressionFactory.Function( "EXTRACT", new[] { new SpannerTimestampExtractExpression(_sqlExpressionFactory, instance, datePart) }, returnType); if (datePart == "DAYOFWEEK") { // Cloud Spanner is 1-based, .NET is 0-based. return(_sqlExpressionFactory.ApplyDefaultTypeMapping(_sqlExpressionFactory.Subtract(extract, _sqlExpressionFactory.Constant(1)))); } return(_sqlExpressionFactory.ApplyDefaultTypeMapping(extract)); } } return(null); }
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> protected override ShapedQueryExpression TranslateCount(ShapedQueryExpression source, LambdaExpression predicate) { Check.NotNull(source, nameof(source)); var selectExpression = (SelectExpression)source.QueryExpression; if (selectExpression.IsDistinct || selectExpression.Limit != null || selectExpression.Offset != null) { return(null); } if (predicate != null) { source = TranslateWhere(source, predicate); if (source == null) { return(null); } } var translation = _sqlExpressionFactory.ApplyDefaultTypeMapping( _sqlExpressionFactory.Function("COUNT", new[] { _sqlExpressionFactory.Constant(1) }, typeof(int))); var projectionMapping = new Dictionary <ProjectionMember, Expression> { { new ProjectionMember(), translation } }; selectExpression.ClearOrdering(); selectExpression.ReplaceProjectionMapping(projectionMapping); return(source.UpdateShaperExpression(new ProjectionBindingExpression(source.QueryExpression, new ProjectionMember(), typeof(int)))); }
public virtual SqlExpression Translate([NotNull] Expression expression) { Check.NotNull(expression, nameof(expression)); var result = Visit(expression); if (result is SqlExpression translation) { if (translation is SqlUnaryExpression sqlUnaryExpression && sqlUnaryExpression.OperatorType == ExpressionType.Convert && sqlUnaryExpression.Type == typeof(object)) { translation = sqlUnaryExpression.Operand; } translation = _sqlExpressionFactory.ApplyDefaultTypeMapping(translation); if (translation.TypeMapping == null) { // The return type is not-mappable hence return null return(null); } _sqlTypeMappingVerifyingExpressionVisitor.Visit(translation); return(translation); } return(null); }
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> protected override ShapedQueryExpression TranslateCount(ShapedQueryExpression source, LambdaExpression predicate) { var selectExpression = (SelectExpression)source.QueryExpression; if (selectExpression.IsDistinct || selectExpression.Limit != null || selectExpression.Offset != null) { throw new InvalidOperationException(CoreStrings.TranslationFailed(predicate.Print())); } if (predicate != null) { source = TranslateWhere(source, predicate); } var translation = _sqlExpressionFactory.ApplyDefaultTypeMapping( _sqlExpressionFactory.Function("COUNT", new[] { _sqlExpressionFactory.Constant(1) }, typeof(int))); var projectionMapping = new Dictionary <ProjectionMember, Expression> { { new ProjectionMember(), translation } }; selectExpression.ClearOrdering(); selectExpression.ReplaceProjectionMapping(projectionMapping); source.ShaperExpression = new ProjectionBindingExpression(source.QueryExpression, new ProjectionMember(), typeof(int)); return(source); }
public virtual SqlExpression Translate(Expression expression) { var result = Visit(expression); if (result is SqlExpression translation) { if (translation is SqlUnaryExpression sqlUnaryExpression && sqlUnaryExpression.OperatorType == ExpressionType.Convert && sqlUnaryExpression.Type == typeof(object)) { translation = sqlUnaryExpression.Operand; } translation = _sqlExpressionFactory.ApplyDefaultTypeMapping(translation); if (translation is SqlConstantExpression && translation.TypeMapping == null) { // Non-mappable constant return(null); } _sqlVerifyingExpressionVisitor.Visit(translation); return(translation); } return(null); }
private SqlExpression TranslateStaticFunction(string function, IReadOnlyList <SqlExpression> arguments, System.Type returnType) { return(_sqlExpressionFactory.ApplyDefaultTypeMapping( _sqlExpressionFactory.Function( function, arguments, returnType))); }
public SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments) { if (method == IPAddressParse) { return(_sqlExpressionFactory.Convert(arguments[0], typeof(IPAddress), _sqlExpressionFactory.FindMapping(typeof(IPAddress)))); } if (method == PhysicalAddressParse) { return(_sqlExpressionFactory.Convert(arguments[0], typeof(PhysicalAddress), _sqlExpressionFactory.FindMapping(typeof(PhysicalAddress)))); } if (method.DeclaringType != typeof(NpgsqlNetworkExtensions)) { return(null); } return(method.Name switch { nameof(NpgsqlNetworkExtensions.LessThan) => _sqlExpressionFactory.LessThan(arguments[1], arguments[2]), nameof(NpgsqlNetworkExtensions.LessThanOrEqual) => _sqlExpressionFactory.LessThanOrEqual(arguments[1], arguments[2]), nameof(NpgsqlNetworkExtensions.GreaterThanOrEqual) => _sqlExpressionFactory.GreaterThanOrEqual(arguments[1], arguments[2]), nameof(NpgsqlNetworkExtensions.GreaterThan) => _sqlExpressionFactory.GreaterThan(arguments[1], arguments[2]), nameof(NpgsqlNetworkExtensions.ContainedBy) => BoolReturningOnTwoNetworkTypes("<<"), nameof(NpgsqlNetworkExtensions.ContainedByOrEqual) => BoolReturningOnTwoNetworkTypes("<<="), nameof(NpgsqlNetworkExtensions.Contains) => BoolReturningOnTwoNetworkTypes(">>"), nameof(NpgsqlNetworkExtensions.ContainsOrEqual) => BoolReturningOnTwoNetworkTypes(">>="), nameof(NpgsqlNetworkExtensions.ContainsOrContainedBy) => BoolReturningOnTwoNetworkTypes("&&"), // TODO: Hack, see #1118 nameof(NpgsqlNetworkExtensions.BitwiseNot) => new SqlUnaryExpression(ExpressionType.Negate, arguments[1], arguments[1].Type, arguments[1].TypeMapping), nameof(NpgsqlNetworkExtensions.BitwiseAnd) => _sqlExpressionFactory.And(arguments[1], arguments[2]), nameof(NpgsqlNetworkExtensions.BitwiseOr) => _sqlExpressionFactory.Or(arguments[1], arguments[2]), // Add/Subtract accept inet + int, so we can't use the default type mapping inference logic which assumes // same-typed operands nameof(NpgsqlNetworkExtensions.Add) => new SqlBinaryExpression( ExpressionType.Add, _sqlExpressionFactory.ApplyDefaultTypeMapping(arguments[1]), _sqlExpressionFactory.ApplyDefaultTypeMapping(arguments[2]), arguments[1].Type, arguments[1].TypeMapping), nameof(NpgsqlNetworkExtensions.Subtract) when arguments[2].Type == typeof(int)
public SqlExpression Translate(SelectExpression selectExpression, Expression expression) { _selectExpression = selectExpression; var translation = (SqlExpression)Visit(expression); _selectExpression = null; translation = _sqlExpressionFactory.ApplyDefaultTypeMapping(translation); _sqlVerifyingExpressionVisitor.Visit(translation); return(translation); }
/// <inheritdoc /> public virtual SqlExpression Translate( IModel model, SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments) { Check.NotNull(model, nameof(model)); Check.NotNull(method, nameof(method)); Check.NotNull(arguments, nameof(arguments)); var dbFunction = model.FindDbFunction(method); if (dbFunction != null) { return(dbFunction.Translation?.Invoke( arguments.Select(e => _sqlExpressionFactory.ApplyDefaultTypeMapping(e)).ToList()) ?? _sqlExpressionFactory.Function( dbFunction.Schema, dbFunction.Name, arguments, nullable: true, argumentsPropagateNullability: arguments.Select(a => false).ToList(), method.ReturnType)); } return(_plugins.Concat(_translators) .Select(t => t.Translate(instance, method, arguments)) .FirstOrDefault(t => t != null)); }
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments) { Check.NotNull(method, nameof(method)); Check.NotNull(arguments, nameof(arguments)); if (_methodInfoDataLengthMapping.Contains(method)) { var argument = arguments[1]; if (argument.TypeMapping == null) { argument = _sqlExpressionFactory.ApplyDefaultTypeMapping(argument); } if (_longReturningTypes.Contains(argument.TypeMapping.StoreType)) { var result = _sqlExpressionFactory.Function( "DATALENGTH", arguments.Skip(1), nullable: true, argumentsPropagateNullability: new[] { true }, typeof(long)); return(_sqlExpressionFactory.Convert(result, method.ReturnType.UnwrapNullableType())); } return(_sqlExpressionFactory.Function( "DATALENGTH", arguments.Skip(1), nullable: true, argumentsPropagateNullability: new[] { true }, method.ReturnType.UnwrapNullableType())); } return(null); }
public virtual SqlExpression Translate( SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments) { if (s_supportedMethods.TryGetValue(method, out var sqlFunctionName)) { if (sqlFunctionName == "ROUND") { // Only rounding mode AwayFromZero can be evaluated server side. // Trying to use a different rounding mode in a query will fail. if (arguments[arguments.Count - 1] is SqlConstantExpression c && c.Value is MidpointRounding mode && mode == MidpointRounding.AwayFromZero) { arguments = arguments.ToList().GetRange(0, arguments.Count - 1); } else { return(null); } } return(_sqlExpressionFactory.ApplyDefaultTypeMapping( _sqlExpressionFactory.Function( sqlFunctionName, arguments, method.ReturnType))); }
private SqlExpression TranslateNoArgFunction(string function, SqlExpression instance, System.Type returnType) { return(_sqlExpressionFactory.ApplyDefaultTypeMapping( _sqlExpressionFactory.Function( function, new[] { instance }, returnType))); }
public SqlExpression Translate(Expression expression) { var translation = (SqlExpression)Visit(expression); if (translation is SqlUnaryExpression sqlUnaryExpression && sqlUnaryExpression.OperatorType == ExpressionType.Convert && sqlUnaryExpression.Type == typeof(object)) { translation = sqlUnaryExpression.Operand; } translation = _sqlExpressionFactory.ApplyDefaultTypeMapping(translation); _sqlVerifyingExpressionVisitor.Visit(translation); return(translation); }
private SqlExpression TranslateSystemFunction(string function, SqlExpression instance, SqlExpression pattern, Type returnType) { Check.NotNull(instance, nameof(instance)); return(_sqlExpressionFactory.ApplyDefaultTypeMapping( _sqlExpressionFactory.Function( function, new[] { instance, pattern }, returnType))); }
protected override ShapedQueryExpression TranslateGroupBy( ShapedQueryExpression source, LambdaExpression keySelector, LambdaExpression elementSelector, LambdaExpression resultSelector) { var selectExpression = (SelectExpression)source.QueryExpression; selectExpression.PrepareForAggregate(); var remappedKeySelector = RemapLambdaBody(source, keySelector); var translatedKey = TranslateGroupingKey(remappedKeySelector) ?? (remappedKeySelector is ConstantExpression ? remappedKeySelector : null); if (translatedKey != null) { if (elementSelector != null) { source = TranslateSelect(source, elementSelector); } var sqlKeySelector = translatedKey is ConstantExpression ? _sqlExpressionFactory.ApplyDefaultTypeMapping(_sqlExpressionFactory.Constant(1)) : translatedKey; var appliedKeySelector = selectExpression.ApplyGrouping(sqlKeySelector); translatedKey = translatedKey is ConstantExpression ? translatedKey : appliedKeySelector; source.ShaperExpression = new GroupByShaperExpression(translatedKey, source.ShaperExpression); if (resultSelector == null) { return(source); } var keyAccessExpression = Expression.MakeMemberAccess( source.ShaperExpression, source.ShaperExpression.Type.GetTypeInfo().GetMember(nameof(IGrouping <int, int> .Key))[0]); var original1 = resultSelector.Parameters[0]; var original2 = resultSelector.Parameters[1]; var newResultSelectorBody = new ReplacingExpressionVisitor( new Dictionary <Expression, Expression> { { original1, keyAccessExpression }, { original2, source.ShaperExpression } }).Visit(resultSelector.Body); source.ShaperExpression = _projectionBindingExpressionVisitor.Translate(selectExpression, newResultSelectorBody); return(source); } throw new InvalidOperationException(); }
public SqlExpression Translate(Expression expression) { var translation = (SqlExpression)Visit(expression); translation = _sqlExpressionFactory.ApplyDefaultTypeMapping(translation); _sqlVerifyingExpressionVisitor.Visit(translation); return(translation); }
protected override Expression VisitExtension(Expression extensionExpression) { if (extensionExpression is SelectExpression selectExpression) { if (IsZero(selectExpression.Limit) && IsZero(selectExpression.Offset)) { return(selectExpression.Update( selectExpression.Projection, selectExpression.Tables, selectExpression.GroupBy.Count > 0 ? selectExpression.Predicate : _sqlExpressionFactory.ApplyDefaultTypeMapping(_sqlExpressionFactory.Constant(false)), selectExpression.GroupBy, selectExpression.GroupBy.Count > 0 ? _sqlExpressionFactory.ApplyDefaultTypeMapping(_sqlExpressionFactory.Constant(false)) : null, new List <OrderingExpression>(0), limit: null, offset: null)); } bool IsZero(SqlExpression?sqlExpression) { switch (sqlExpression) { case SqlConstantExpression constant when constant.Value is int intValue: return(intValue == 0); case SqlParameterExpression parameter: _canCache = false; return(_parameterValues[parameter.Name] is int value && value == 0); default: return(false); } } } return(base.VisitExtension(extensionExpression)); }
protected override ShapedQueryExpression TranslateAverage(ShapedQueryExpression source, LambdaExpression selector, Type resultType) { var selectExpression = (SelectExpression)source.QueryExpression; if (selectExpression.Limit != null || selectExpression.Offset != null) { selectExpression.PushdownIntoSubQuery(); } if (selector != null) { source = TranslateSelect(source, selector); } var projection = (SqlExpression)selectExpression.GetProjectionExpression(new ProjectionMember()); var inputType = projection.Type.UnwrapNullableType(); if (inputType == typeof(int) || inputType == typeof(long)) { projection = _sqlExpressionFactory.ApplyDefaultTypeMapping( _sqlExpressionFactory.Convert(projection, typeof(double))); } if (inputType == typeof(float)) { projection = _sqlExpressionFactory.Convert( _sqlExpressionFactory.Function( "AVG", new[] { projection }, typeof(double), null), projection.Type, projection.TypeMapping); } else { projection = _sqlExpressionFactory.Function( "AVG", new[] { projection }, projection.Type, projection.TypeMapping); } return(AggregateResultShaper(source, projection, throwOnNullResult: true, resultType)); }
private SqlExpression ConvertToValue(SqlExpression sqlExpression, bool condition) => condition ? _sqlExpressionFactory.Case( new[] { new CaseWhenClause( SimplifyNegatedBinary(sqlExpression), _sqlExpressionFactory.ApplyDefaultTypeMapping(_sqlExpressionFactory.Constant(true))) }, _sqlExpressionFactory.Constant(false)) : sqlExpression;
public virtual SqlExpression?Translate( IModel model, SqlExpression?instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments, IDiagnosticsLogger <DbLoggerCategory.Query> logger) { Check.NotNull(model, nameof(model)); Check.NotNull(method, nameof(method)); Check.NotNull(arguments, nameof(arguments)); Check.NotNull(logger, nameof(logger)); var dbFunction = model.FindDbFunction(method); if (dbFunction != null) { if (dbFunction.Translation != null) { return(dbFunction.Translation.Invoke( arguments.Select(e => _sqlExpressionFactory.ApplyDefaultTypeMapping(e)).ToList())); } var argumentsPropagateNullability = dbFunction.Parameters.Select(p => p.PropagatesNullability); if (dbFunction.IsBuiltIn) { return(_sqlExpressionFactory.Function( dbFunction.Name, arguments, dbFunction.IsNullable, argumentsPropagateNullability, method.ReturnType.UnwrapNullableType())); } return(dbFunction.Schema is null ? _sqlExpressionFactory.Function( dbFunction.Name, arguments, dbFunction.IsNullable, argumentsPropagateNullability, method.ReturnType.UnwrapNullableType()) : _sqlExpressionFactory.Function( dbFunction.Schema, dbFunction.Name, arguments, dbFunction.IsNullable, argumentsPropagateNullability, method.ReturnType.UnwrapNullableType())); } return(_plugins.Concat(_translators) .Select(t => t.Translate(instance, method, arguments, logger)) .FirstOrDefault(t => t != null)); }
public override SqlExpression TranslateLongCount(Expression expression = null) { if (expression != null) { // TODO: Translate Count with predicate for GroupBy return(null); } return(_sqlExpressionFactory.ApplyDefaultTypeMapping( _sqlExpressionFactory.Function("COUNT_BIG", new[] { _sqlExpressionFactory.Fragment("*") }, typeof(long)))); }
private Expression ConvertToValue(SqlExpression sqlExpression, bool condition) { return(condition ? _sqlExpressionFactory.Case(new[] { new CaseWhenClause( sqlExpression, _sqlExpressionFactory.ApplyDefaultTypeMapping(_sqlExpressionFactory.Constant(true))) }, _sqlExpressionFactory.Constant(false)) : sqlExpression); }
/// <summary> /// This API supports the Entity Framework Core infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> public SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments) { if (_methodInfos.Any(m => Equals(method, m))) { var match = _sqlExpressionFactory.ApplyDefaultTypeMapping(arguments[1]); var pattern = InferStringTypeMappingOrApplyDefault( arguments[2], match.TypeMapping); var excapeChar = arguments.Count == 4 ? InferStringTypeMappingOrApplyDefault( arguments[3], match.TypeMapping) : null; return(_sqlExpressionFactory.Like( match, pattern, excapeChar)); } return(null); }
/// <summary> /// This API supports the Entity Framework Core infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> public SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments, IDiagnosticsLogger <Microsoft.EntityFrameworkCore.DbLoggerCategory.Query> logger) { if (_methodInfos.Any(m => Equals(method, m))) { var match = _sqlExpressionFactory.ApplyDefaultTypeMapping(arguments[1]); var pattern = InferStringTypeMappingOrApplyDefault( arguments[2], match.TypeMapping); var excapeChar = arguments.Count == 4 ? InferStringTypeMappingOrApplyDefault( arguments[3], match.TypeMapping) : null; return(_sqlExpressionFactory.Like( match, pattern, excapeChar)); } return(null); }
public SqlExpression Translate(Expression expression) { var result = Visit(expression); if (result is SqlExpression translation) { translation = _sqlExpressionFactory.ApplyDefaultTypeMapping(translation); _sqlVerifyingExpressionVisitor.Visit(translation); return(translation); } return(null); }
/// <inheritdoc /> public SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments) { if (!MethodInfoDatePartMapping.TryGetValue(method, out var datePart)) { return(null); } var interval = arguments[0]; if (instance is null || interval is null) { return(null); } // Note: ideally we'd simply generate a PostgreSQL interval expression, but the .NET mapping of that is TimeSpan, // which does not work for months, years, etc. So we generate special fragments instead. if (interval is SqlConstantExpression constantExpression) { // We generate constant intervals as INTERVAL '1 days' if (constantExpression.Type == typeof(double) && ((double)constantExpression.Value >= int.MaxValue || (double)constantExpression.Value <= int.MinValue)) { return(null); } interval = _sqlExpressionFactory.Fragment(FormattableString.Invariant($"INTERVAL '{constantExpression.Value} {datePart}'")); } else { // For non-constants, we can't parameterize INTERVAL '1 days'. Instead, we use CAST($1 || ' days' AS interval). // Note that a make_interval() function also exists, but accepts only int (for all fields except for // seconds), so we don't use it. // Note: we instantiate SqlBinaryExpression manually rather than via sqlExpressionFactory because // of the non-standard Add expression (concatenate int with text) interval = _sqlExpressionFactory.Convert( new SqlBinaryExpression( ExpressionType.Add, _sqlExpressionFactory.ApplyDefaultTypeMapping(interval), _sqlExpressionFactory.Constant(' ' + datePart, _textMapping), typeof(string), _textMapping), typeof(TimeSpan), _intervalMapping); } return(_sqlExpressionFactory.Add(instance, interval, instance.TypeMapping)); }
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public virtual SqlExpression?Translate( SqlExpression?instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments, IDiagnosticsLogger <DbLoggerCategory.Query> logger) { Check.NotNull(method, nameof(method)); Check.NotNull(arguments, nameof(arguments)); Check.NotNull(logger, nameof(logger)); if (_functionMapping.TryGetValue(method, out var functionName)) { var propertyReference = arguments[1]; if (!(propertyReference is ColumnExpression)) { throw new InvalidOperationException(SqlServerStrings.InvalidColumnNameForFreeText); } var typeMapping = propertyReference.TypeMapping; var freeText = propertyReference.Type == arguments[2].Type ? _sqlExpressionFactory.ApplyTypeMapping(arguments[2], typeMapping) : _sqlExpressionFactory.ApplyDefaultTypeMapping(arguments[2]); var functionArguments = new List <SqlExpression> { propertyReference, freeText }; if (arguments.Count == 4) { functionArguments.Add( _sqlExpressionFactory.Fragment($"LANGUAGE {((SqlConstantExpression)arguments[3]).Value}")); } return(_sqlExpressionFactory.Function( functionName, functionArguments, nullable: true, // TODO: don't propagate for now argumentsPropagateNullability: functionArguments.Select(a => false).ToList(), typeof(bool))); } return(null); }
public virtual SqlExpression Translate(IModel model, SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments) { var dbFunction = model.FindDbFunction(method); if (dbFunction != null) { return(dbFunction.Translation?.Invoke( arguments.Select(e => _sqlExpressionFactory.ApplyDefaultTypeMapping(e)).ToList()) ?? _sqlExpressionFactory.Function( dbFunction.Schema, dbFunction.Name, arguments, method.ReturnType)); } return(_plugins.Concat(_translators) .Select(t => t.Translate(instance, method, arguments)) .FirstOrDefault(t => t != null)); }
private SqlExpression TranslateInternal(Expression expression) { var result = Visit(expression); if (result is SqlExpression translation) { translation = _sqlExpressionFactory.ApplyDefaultTypeMapping(translation); if (translation.TypeMapping == null) { // The return type is not-mappable hence return null return(null); } _sqlVerifyingExpressionVisitor.Visit(translation); return(translation); } return(null); }