Support for table names in SpEL expressions.

SpEL expressions in queries get processed in two steps:

1. First SpEL expressions outside parameters are detected and processed.
This is done with a `StandardEvaluationContext` with the variables `tableName` and `qualifiedTableName` added.
This step is introduced by this commit.

2. Parameters made up by SpEL expressions are processed as usual.

Closes #1856
Original pull request #1863
This commit is contained in:
Jens Schauder
2024-08-20 11:08:08 +02:00
committed by Mark Paluch
parent 4221840538
commit f937738038
16 changed files with 574 additions and 24 deletions

View File

@@ -176,7 +176,10 @@ For example if the `User` from the example above has an `address` with the prope
WARNING: Note that String-based queries do not support pagination nor accept `Sort`, `PageRequest`, and `Limit` as a query parameter as for these queries the query would be required to be rewritten.
If you want to apply limiting, please express this intent using SQL and bind the appropriate parameters to the query yourself.
Queries may contain SpEL expressions where bind variables are allowed.
Queries may contain SpEL expressions.
There are two variants that are evaluated differently.
In the first variant a SpEL expression is prefixed with `:` and used like a bind variable.
Such a SpEL expression will get replaced with a bind variable and the variable gets bound to the result of the SpEL expression.
.Use a SpEL in a query
@@ -189,6 +192,18 @@ Person findWithSpEL(PersonRef person);
This can be used to access members of a parameter, as demonstrated in the example above.
For more involved use cases an `EvaluationContextExtension` can be made available in the application context, which in turn can make any object available in to the SpEL.
The other variant can be used anywhere in the query and the result of evaluating the query will replace the expression in the query string.
.Use a SpEL in a query
[source,java]
----
@Query("SELECT * FROM #{tableName} WHERE id = :id")
Person findWithSpEL(PersonRef person);
----
It is evaluated once before the first execution and uses a `StandardEvaluationContext` with the two variables `tableName` and `qualifiedTableName` added.
This use is most useful when table names are dynamic themselves, because they use SpEL expressions as well.
NOTE: Spring fully supports Java 8s parameter name discovery based on the `-parameters` compiler flag.
By using this flag in your build as an alternative to debug information, you can omit the `@Param` annotation for named parameters.

View File

@@ -207,6 +207,8 @@ By using this flag in your build as an alternative to debug information, you can
=== Queries with SpEL Expressions
Query string definitions can be used together with SpEL expressions to create dynamic queries at runtime.
SpEL expressions can be used in two ways.
SpEL expressions can provide predicate values which are evaluated right before running the query.
Expressions expose method arguments through an array that contains all the arguments.
@@ -218,12 +220,24 @@ to declare the predicate value for `lastname` (which is equivalent to the `:last
include::example$r2dbc/PersonRepository.java[tags=spel]
----
SpEL in query strings can be a powerful way to enhance queries.
However, they can also accept a broad range of unwanted arguments.
You should make sure to sanitize strings before passing them to the query to avoid unwanted changes to your query.
Expression support is extensible through the Query SPI: `org.springframework.data.spel.spi.EvaluationContextExtension`.
This Expression support is extensible through the Query SPI: `org.springframework.data.spel.spi.EvaluationContextExtension`.
The Query SPI can contribute properties and functions and can customize the root object.
Extensions are retrieved from the application context at the time of SpEL evaluation when the query is built.
TIP: When using SpEL expressions in combination with plain parameters, use named parameter notation instead of native bind markers to ensure a proper binding order.
The other way to use Expression is in the middle of query, independent of parameters.
The result of evaluating the query will replace the expression in the query string.
.Use a SpEL in a query
[source,java,indent=0]
----
include::example$r2dbc/PersonRepository.java[tags=spel2]
----
It is evaluated once before the first execution and uses a `StandardEvaluationContext` with the two variables `tableName` and `qualifiedTableName` added.
This use is most useful when table names are dynamic themselves, because they use SpEL expressions as well.
SpEL in query strings can be a powerful way to enhance queries.
However, they can also accept a broad range of unwanted arguments.
You should make sure to sanitize strings before passing them to the query to avoid unwanted changes to your query.