diff --git a/docs/configuration/in-list-optimization.mdx b/docs/configuration/in-list-optimization.mdx
new file mode 100644
index 000000000..cd02fb6ac
--- /dev/null
+++ b/docs/configuration/in-list-optimization.mdx
@@ -0,0 +1,93 @@
+---
+sidebar_position: 15
+title: In List Predicate Optimization
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+:::caution
+This article only explains how to enable the relevant options.
+
+As for what these options are used for, please refer to [Query Chapter/DSL Expression/IN LIST/Optimization](../query/expression#optimization), this article will not repeat it.
+:::
+
+## Enable Padding Optimization
+
+Two ways to enable:
+
+- If you are using the Jimmer Spring Boot Starter, modify `application.yml` (or `application.properties`) as follows:
+
+ ```sh title="application.yml"
+ jimmer:
+ #highlight-next-line
+ in-list-padding-enabled: true
+ ```
+
+- If you are not using the Jimmer Spring Boot Starter, you need to call the following API when creating the `sqlClient`:
+
+
+
+
+ ```java
+ JSqlClient sqlClient = JSqlClient
+ .newBuilder()
+ // highlight-next-line
+ .setInListPaddingEnabled(true)
+ // ...omitted other configurations...
+ .build();
+ ```
+
+
+
+
+ ```kotlin
+ val sqlClient = newKSqlClient {
+ // highlight-next-line
+ setInListPaddingEnabled(true)
+ // ...omitted other configurations...
+ }
+ ```
+
+
+
+
+## Enable Any Equality Optimization
+
+Two ways to enable:
+
+- If you are using the Jimmer Spring Boot Starter, modify `application.yml` (or `application.properties`) as follows:
+
+ ```sh title="application.yml"
+ jimmer:
+ #highlight-next-line
+ in-list-to-any-equality-enabled: true
+ ```
+
+- If you are not using the Jimmer Spring Boot Starter, you need to call the following API when creating the `sqlClient`:
+
+
+
+
+ ```java
+ JSqlClient sqlClient = JSqlClient
+ .newBuilder()
+ // highlight-next-line
+ .setInListToAnyEqualityEnabled(true)
+ // ...omitted other configurations...
+ .build();
+ ```
+
+
+
+
+ ```kotlin
+ val sqlClient = newKSqlClient {
+ // highlight-next-line
+ setInListToAnyEqualityEnabled(true)
+ // ...omitted other configurations...
+ }
+ ```
+
+
+
\ No newline at end of file
diff --git a/docs/mutation/save-command/other.mdx b/docs/mutation/save-command/other.mdx
index 2dadb6235..18bd9bec3 100644
--- a/docs/mutation/save-command/other.mdx
+++ b/docs/mutation/save-command/other.mdx
@@ -148,87 +148,3 @@ The explanation is:
- New association between `Book(id=3L)` and `Author(id=3L)`.
- New association between `Book(id=3L)` and `Author(id=1000L)`.
-
-## AppendOnly Mode
-
-:::warning
-This is an immature API provided in early deficient documentation to address the inability of initial users to understand why save commands need keys.
-
-It violates the core design philosophy of save commands, leading to severely degraded capabilities, and may be removed in the future. Usage should be avoided.
-:::
-
-There are two usage methods:
-
-- Set specific association properties to AppendOnly mode
-
-
-
-
- ```java
- Book book = ...
- sqlClient
- .getEntities()
- .saveCommand(book)
- // highlight-next-line
- .setAppendOnly(BookProps.AUTHORS)
- .execute();
- ```
-
-
-
-
- ```kotlin
- val book = ...
- sqlClient.saveBook(book) {
- // highlight-next-line
- setAppendOnly(BookProps.AUTHORS)
- }
- ```
-
-
-
-
-- Set all association properties to AppendOnly mode
-
-
-
-
- ```java
- Book book = ...
- sqlClient
- .getEntities()
- .saveCommand(book)
- // highlight-next-line
- .setAppendOnlyAll()
- .execute();
- ```
-
-
-
-
- ```kotlin
- val book = ...
- sqlClient.saveBook(book) {
- // highlight-next-line
- setAppendOnlyAll()
- }
- ```
-
-
-
-
-Regardless of usage, once enabled, the consequences are:
-
-- Idempotency of saving associated objects is lost.
-
- This config allows associated objects to have neither id nor key properties, resulting in unconditional insertion of associated objects.
-
-- Associated properties lose [dissociation](./dissociation) capability.
-
- This config will only insert or update the associated objects provided by the user, and will not dissociate other associated objects existing in the database but absent from the data structure to be saved.
-
-:::info
-The author believes this API runs counter to the core philosophy of save commands, and should not be retained.
-
-You are welcome to share your insights. Please see [Discussions](../../resource/discuss).
-:::
\ No newline at end of file
diff --git a/docs/object/view/dto-language.mdx b/docs/object/view/dto-language.mdx
index 8e18b214a..ee5526fd1 100644
--- a/docs/object/view/dto-language.mdx
+++ b/docs/object/view/dto-language.mdx
@@ -323,6 +323,15 @@ Compared with Output DTO, Input DTO has the following differences:
- The input DTO can only define savable properties, such as simple properties, ordinary ORM associations, and id-view properties. Unsavable properties such as transient properties, formula properties, computed properties, and remote associations cannot be defined, otherwise it will cause compilation errors.
+- Input DTO provides comprehensive and powerful support for nullable properties.
+
+ :::tip
+ For properties that are allowed to be null in the original entity, how to map them through Input DTO is a complex topic.
+ Jimmer provides comprehensive and powerful support.
+
+ Please refer to [Modification/Save Command/Input DTO/Handle Null Values](../../mutation/save-command/input-dto/null-handling).
+ :::
+
### 3.3 specification-specific functionalities
The role of `specification` is similar to `input`, used to decorate input types, but `specification` does not provide the ability to convert between entity objects, but is used as a query parameter to support [super QBE queries](../../query/super_qbe).
@@ -520,20 +529,13 @@ input UpdateBookInput {
- When the original property in the entity allows null
- For originally nullable properties in entities, if the corresponding property in the DTO object is null, then when converting the DTO object to the entity object:
-
- - If the `input` type is not modified by the `dynamic` keyword, the original property in the entity object will be assigned to null.
-
- - If the `input` type is modified by the `dynamic` keyword, for example:
-
- ```sh title="BookStroe.dto"
- #highlight-next-line
- dynamic input BookInput {
- #allScalars(this)?
- }
- ```
-
- The original properties in the entity object will not be assigned.
+ :::tip
+ For properties that are allowed to be null in the original entity, how to map them through Input DTO is a complex topic.
+ Jimmer provides comprehensive and powerful support.
+
+ Due to length limitations, this issue forms a separate article.
+ Please refer to [Modification/Save Command/Input DTO/Handle Null Values](../../mutation/save-command/input-dto/null-handling).
+ :::
### 7.2. `!`
@@ -1481,3 +1483,11 @@ If a property in the DTO overrides an abstract property in the interface, then i
Apart from this, the DTO language does not perform much validation on interface implementation. If the user makes other mistakes, it will result in generating incorrect Java/Kotlin types, which will be handled by the Java/Kotlin compiler.
:::
+
+## 12. Related Links
+
+As mentioned earlier, the DTO language has two more powerful features that are not discussed in depth in this article due to length limitations, but have been separated into other documents. Here we emphasize them again:
+
+- [Handling Null Values in Input DTO](../../mutation/save-command/input-dto/null-handling)
+
+- [Specification DTO, Super QBE](../../query/super_qbe)
\ No newline at end of file
diff --git a/docs/query/expression.mdx b/docs/query/expression.mdx
index 7c212459c..5e34f96a5 100644
--- a/docs/query/expression.mdx
+++ b/docs/query/expression.mdx
@@ -829,6 +829,249 @@ Besides used with collections, `in` can also be used with subqueries.
This will be covered in detail in docs about [subqueries](../query/sub-query).
:::
+### Optimization
+
+Jimmer provides 3 optimizations for the `in list` expression:
+
+- Single value optimization
+- Padding optimization
+- Any equality optimization
+
+1. Single value optimization
+
+ When the list length is 1, `in(?)` will be automatically rewritten as `= ?`, and `not in(?)` will be automatically rewritten as `<> ?`. For example:
+
+
+
+
+ ```java
+ where(
+ Expression.tuple(
+ book.name(),
+ book.edition()
+ ).in(
+ Arrays.asList(
+ new Tuple2<>("SQL in Action", 1)
+ )
+ )
+ );
+ ```
+
+
+
+
+ ```kotlin
+ where(
+ tuple(
+ table.name,
+ table.edition
+ ) valueIn listOf(
+ Tuple2("SQL in Action", 1)
+ )
+ )
+ ```
+
+
+
+
+ The generated SQL condition:
+ ```sql
+ where
+ (tb_1_.NAME, tb_1_.EDITION) =
+ (? /* SQL in Action */, ? /* 1 */)
+ ```
+
+2. Padding optimization
+
+ To support padding optimization, Jimmer provides a switch that can be enabled in two ways:
+
+ - If you are using the Jimmer Spring Boot Starter, modify `application.yml` (or `application.properties`) as follows:
+
+ ```sh title="application.yml"
+ jimmer:
+ #highlight-next-line
+ in-list-padding-enabled: true
+ ```
+
+ - If you are not using the Jimmer Spring Boot Starter, you need to call the following API when creating the `sqlClient`:
+
+
+
+
+ ```java
+ JSqlClient sqlClient = JSqlClient
+ .newBuilder()
+ // highlight-next-line
+ .setInListPaddingEnabled(true)
+ // ...omitted other configurations...
+ .build();
+ ```
+
+
+
+
+ ```kotlin
+ val sqlClient = newKSqlClient {
+ // highlight-next-line
+ setInListPaddingEnabled(true)
+ // ...omitted other configurations...
+ }
+ ```
+
+
+
+
+ Once this switch is enabled, Jimmer will ensure that the list length is a power of 2 (2, 4, 6, 8, 16, 32, ...), thereby significantly reducing the diversity of SQL and increasing the diversity of database execution plan caching. For example:
+
+
+
+
+ ```java
+ where(
+ Expression.tuple(
+ book.name(),
+ book.edition()
+ ).in(
+ Arrays.asList(
+ new Tuple2<>("SQL in Action", 1),
+ new Tuple2<>("SQL in Action", 2),
+ new Tuple2<>("Java in Action", 1)
+ )
+ )
+ );
+ ```
+
+
+
+
+ ```kotlin
+ where(
+ tuple(
+ table.name,
+ table.edition
+ ) valueIn listOf(
+ Tuple2("SQL in Action", 1),
+ Tuple2("SQL in Action", 2),
+ Tuple2("Java in Action", 1)
+ )
+ )
+ ```
+
+
+
+
+ In this example, the list length is 3, which is not a power of 2. The nearest power of 2 to 3 is 4, so Jimmer will repeat the last item in the list, eventually making the list length 4. The generated SQL condition is as follows:
+
+ ```sql
+ where (tb_1_.NAME, tb_1_.EDITION) in (
+
+ // Original list
+ (? /* SQL in Action */, ? /* 1 */),
+ (? /* SQL in Action */, ? /* 2 */),
+ (? /* Java in Action */, ? /* 1 */),
+
+ // Repeat the last item in the original list
+ // to make the list length a power of 2
+ // highlight-next-line
+ (? /* Java in Action */, ? /* 1 */)
+ )
+ ```
+
+3. Any equality optimization
+
+ This optimization is better tested by the previously discussed padding optimization, but it has two limitations:
+
+ - Currently, it can only optimize single column in
+
+ - The database needs to support the `= any(?)` expression, i.e., the `isAnyEqualityOfArraySupported()` method of the implementation class of `org.babyfish.jimmer.sql.dialect.Dialect` needs to return true
+
+ > Currently, the dialects that support this behavior are:
+ >
+ > - org.babyfish.jimmer.sql.dialect.H2Dialect
+ > - org.babyfish.jimmer.sql.dialect.PostgresDialect
+
+ For this, Jimmer provides a switch that can be enabled in two ways:
+
+ - If you are using the Jimmer Spring Boot Starter, modify `application.yml` (or `application.properties`) as follows:
+
+ ```sh title="application.yml"
+ jimmer:
+ #highlight-next-line
+ in-list-to-any-equality-enabled: true
+ ```
+
+ - If you are not using the Jimmer Spring Boot Starter, you need to call the following API when creating the `sqlClient`:
+
+
+
+
+ ```java
+ JSqlClient sqlClient = JSqlClient
+ .newBuilder()
+ // highlight-next-line
+ .setInListToAnyEqualityEnabled(true)
+ // ...omitted other configurations...
+ .build();
+ ```
+
+
+
+
+ ```kotlin
+ val sqlClient = newKSqlClient {
+ // highlight-next-line
+ setInListToAnyEqualityEnabled(true)
+ // ...omitted other configurations...
+ }
+ ```
+
+
+
+
+ :::warning
+ If the current `org.babyfish.jimmer.sql.dialect.Dialect` implementation class's `isAnyEqualityOfArraySupported()` method returns false (does not support this feature),
+ this configuration will cause an exception, and the `sqlClient` cannot be created, and the application cannot start.
+ :::
+
+
+
+
+ ```java
+ where(
+ book.name().in(
+ Arrays.asList(
+ "SQL in Action",
+ "Java in Action"
+ )
+ )
+ );
+ ```
+
+
+
+
+ ```kotlin
+ where(
+ table.name valueIn listOf(
+ "SQL in Action",
+ "Java in Action"
+ )
+ )
+ ```
+
+
+
+
+ The generated SQL condition:
+
+ ```sql
+ where tb_1_.NAME = any(
+ ? /* [SQL in Action, Java in Action] */
+ )
+ ```
+
+ Here, the entire list is treated as a whole and passed as an array-type parameter.
+
## AND, OR, NOT
### AND
diff --git a/docs/quick-view/get-started/create-project.mdx b/docs/quick-view/get-started/create-project.mdx
index 1911280ee..2cc4fa5cf 100644
--- a/docs/quick-view/get-started/create-project.mdx
+++ b/docs/quick-view/get-started/create-project.mdx
@@ -57,7 +57,7 @@ Modify build.gradle or pom.xml to add dependencies:
```xml title="pom.xml"
- 0.8.115
+ 0.8.130
@@ -75,7 +75,7 @@ Modify build.gradle or pom.xml to add dependencies:
```groovy
ext {
- jimmerVersion = '0.8.115'
+ jimmerVersion = '0.8.130'
}
dependencies {
@@ -90,7 +90,7 @@ dependencies {
```kotlin
-val jimmerVersion = "0.8.115"
+val jimmerVersion = "0.8.130"
dependencies {
@@ -114,7 +114,7 @@ plugins {
jimmer {
// Set the Jimmer dependency version, where you can also use version range expressions such as "latest.release" or "0.+"
- version = "0.8.115"
+ version = "0.8.130"
}
```
@@ -132,7 +132,7 @@ plugins {
jimmer {
// Set the Jimmer dependency version, where you can also use version range expressions such as "latest.release" or "0.+"
- version = "0.8.115"
+ version = "0.8.130"
}
```
diff --git a/docs/showcase/where/dynamic-join.mdx b/docs/showcase/where/dynamic-join.mdx
index 5c5698292..9441b440d 100644
--- a/docs/showcase/where/dynamic-join.mdx
+++ b/docs/showcase/where/dynamic-join.mdx
@@ -125,7 +125,7 @@ where
类似Java中`table.store()`或Kotlin`table.store`这样的连接路径,会被渲染成SQL的内连接,而非外连接,这是因为
:::info
-内连接比外链接拥有更好的性能!
+内连接比外连接拥有更好的性能!
:::
:::caution
diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/configuration/in-list-optimization.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/configuration/in-list-optimization.mdx
new file mode 100644
index 000000000..aec50f0d0
--- /dev/null
+++ b/i18n/zh/docusaurus-plugin-content-docs/current/configuration/in-list-optimization.mdx
@@ -0,0 +1,93 @@
+---
+sidebar_position: 15
+title: In List谓词优化
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+:::caution
+本文只阐述如何开启相关选项。
+
+至于选项究竟有何用,请参见[查询篇/DSL表达式/IN LIST/优化](../query/expression#优化),本文不做重复
+:::
+
+## 开启Padding优化
+
+两种开启方式
+
+- 如果使用了Jimmer的Spring Boot Starter,修改`application.yml` *(或`application.properties`)*如下
+
+ ```sh title="application.yml"
+ jimmer:
+ #highlight-next-line
+ in-list-padding-enabled: true
+ ```
+
+- 如果没有使用了Jimmer的Spring Boot Starter,则需要在创建`sqlClient`时调用如下API
+
+
+
+
+ ```java
+ JSqlClient sqlClient = JSqlClient
+ .newBuilder()
+ // highlight-next-line
+ .setInListPaddingEnabled(true)
+ // ...省略其他配置...
+ .build();
+ ```
+
+
+
+
+ ```kotlin
+ val sqlClient = newKSqlClient {
+ // highlight-next-line
+ setInListPaddingEnabled(true)
+ // ...省略其他配置...
+ }
+ ```
+
+
+
+
+## 开启Any等式优化
+
+如下两种开启方式
+
+- 如果使用了Jimmer的Spring Boot Starter,修改`application.yml` *(或`application.properties`)*如下
+
+ ```sh title="application.yml"
+ jimmer:
+ #highlight-next-line
+ in-list-to-any-equality-enabled: true
+ ```
+
+- 如果没有使用了Jimmer的Spring Boot Starter,则需要在创建`sqlClient`时调用如下API
+
+
+
+
+ ```java
+ JSqlClient sqlClient = JSqlClient
+ .newBuilder()
+ // highlight-next-line
+ .setInListToAnyEqualityEnabled(true)
+ // ...省略其他配置...
+ .build();
+ ```
+
+
+
+
+ ```kotlin
+ val sqlClient = newKSqlClient {
+ // highlight-next-line
+ setInListToAnyEqualityEnabled(true)
+ // ...省略其他配置...
+ }
+ ```
+
+
+
\ No newline at end of file
diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/mutation/save-command/other.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/mutation/save-command/other.mdx
index a5870ce34..8b65958e1 100644
--- a/i18n/zh/docusaurus-plugin-content-docs/current/mutation/save-command/other.mdx
+++ b/i18n/zh/docusaurus-plugin-content-docs/current/mutation/save-command/other.mdx
@@ -148,87 +148,3 @@ println(
- `Book(id=3L)`和`Author(id=3L)`之间新建关联
- `Book(id=3L)`和`Author(id=1000L)`之间新建关联
-
-## AppendOnly模式
-
-:::warning
-早期文档极不健全,为解决首批用户无法理解为什么保存指令需要key的问题而提供的不成熟API。
-
-该API违背了保存指令的设计初衷,导致了功能严重退化,以后有可能被删除,应该避免使用。
-:::
-
-有两种使用方法
-
-- 设置特定的关联属性为AppendOnly模式
-
-
-
-
- ```java
- Book book = ...略...;
- sqlClient
- .getEntities()
- .saveCommand(book)
- // highlight-next-line
- .setAppendOnly(BookProps.AUTHORS)
- .execute();
- ```
-
-
-
-
- ```kotlin
- val book = ...略...
- sqlClient.saveBook(book) {
- // highlight-next-line
- setAppendOnly(BookProps.AUTHORS)
- }
- ```
-
-
-
-
-- 设置所有关联属性为AppendOnly模式
-
-
-
-
- ```java
- Book book = ...略...;
- sqlClient
- .getEntities()
- .saveCommand(book)
- // highlight-next-line
- .setAppendOnlyAll()
- .execute();
- ```
-
-
-
-
- ```kotlin
- val book = ...略...
- sqlClient.saveBook(book) {
- // highlight-next-line
- setAppendOnlyAll()
- }
- ```
-
-
-
-
-无论哪种用法,一旦使用,后果如下:
-
-- 关联对象的保存不再支持幂等性。
-
- 该配置允许关联对象既无id属性也无key属性,一旦出现这种情况,无条件插入关联对象。
-
-- 关联属性丧失[脱钩能力](./dissociation)。
-
- 该配置只会对用户给定的关联对象进行insert或update,不会对存在于数据库中但不存在于用户要保存的数据结构中的其它关联对象进行[脱钩操作](./dissociation)。
-
-:::info
-作者本人认为这个API和保存指令的核心理念背道而驰,因此不应该被保留。
-
-欢迎你的提出你的见解。请参见[讨论](../../resource/discuss)
-:::
\ No newline at end of file
diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/object/view/dto-language.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/object/view/dto-language.mdx
index eaf4ea992..8fdcf9112 100644
--- a/i18n/zh/docusaurus-plugin-content-docs/current/object/view/dto-language.mdx
+++ b/i18n/zh/docusaurus-plugin-content-docs/current/object/view/dto-language.mdx
@@ -321,6 +321,14 @@ val anotherEntity: Book = dto.toEntity()
- input DTO中只能定义可以保存的属性,如简单属性、普通ORM关联属性和id-view属性。 不能定义无法保存的属性,如transient属性、公式属性、计算属性和远程关联,否则会导致编译错误。
+- input DTO对nullable属性有强大的全面的支持
+
+ :::tip
+ 对于原实体中允许为null的属性而言,如何通过Input DTO映射是一个复杂的话题,Jimmer提供全面和强大的支持。
+
+ 请参见[修改篇/保持指令/Input DTO/处理空值](../../mutation/save-command/input-dto/null-handling)。
+ :::
+
### 3.3 specification特有功能
`specification`和`input`的作用类似,用于修饰输入类型,但`specification`不提供和实体对象相互转化的能力,而是被用作支持[超级QBE查询](../../query/super_qbe)。
@@ -517,20 +525,11 @@ input UpdateBookInput {
- 当实体的原属性允许为null时
- 对于实体中的本就允许为null原始属性而言,如果DTO对象的对应属性为null,那么将改DTO对象转化为实体对象后:
-
- - 如果`input`类型未被`dynamic`关键字修饰,那么实体对象中原始属性会被赋为null。
-
- - 如果`input`类型被`dynamic`关键字修饰,例如
-
- ```sh title="BookStroe.dto"
- #highlight-next-line
- dynamic input BookInput {
- #allScalars(this)?
- }
- ```
-
- 那么,实体对象中原始属性不会被赋值。
+ :::tip
+ 对于原实体中允许为null的属性而言,如何通过Input DTO映射是一个复杂的话题,Jimmer提供全面和强大的支持。
+
+ 限于篇幅问题,这个问题单独形成一篇文章,请参见[修改篇/保持指令/Input DTO/处理空值](../../mutation/save-command/input-dto/null-handling)。
+ :::
### 7.2. `!`
@@ -1473,4 +1472,12 @@ open class BookView(
如果DTO中的某个属性覆盖了接口的抽象属性,那么在自动生成的Java/Kotlin类型中,该属性会被添加`@Override`注解 *(Java)* 或`override`关键字 *(Kotlin)*。
除此之外,DTO语言对接口实现的验证并不多。如果用户犯了其他错误,将会导致生成错误的Java/Kotlin类型,由Java/Kotlin编译器负责处理。
-:::
\ No newline at end of file
+:::
+
+## 12. 相关链接
+
+前文提到,DTO语言还有两个强大的功能,由于篇幅原因,未在本文中深入讨论,而是被独立成了其他文档。这里再次强调一次。
+
+- [在Input DTO中处理空值](../../mutation/save-command/input-dto/null-handling)
+
+- [Specification DTO,超级QBE](../../query/super_qbe)
\ No newline at end of file
diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/query/dynamic-join/chain-style.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/query/dynamic-join/chain-style.mdx
index 6d19970ee..a951481ad 100644
--- a/i18n/zh/docusaurus-plugin-content-docs/current/query/dynamic-join/chain-style.mdx
+++ b/i18n/zh/docusaurus-plugin-content-docs/current/query/dynamic-join/chain-style.mdx
@@ -114,7 +114,7 @@ inner join CITY tb_3_ // `.city`
tb_1_.EDITION desc
```
-## 外链接
+## 外连接
上面的例子中,关联路径中`.store`和`.city`都表示内连接。
diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/query/expression.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/query/expression.mdx
index b3d9c29cc..649cb8dfc 100644
--- a/i18n/zh/docusaurus-plugin-content-docs/current/query/expression.mdx
+++ b/i18n/zh/docusaurus-plugin-content-docs/current/query/expression.mdx
@@ -813,7 +813,10 @@ where(
生成的SQL条件
```sql
where (tb_1_.NAME, tb_1_.EDITION) in (
- (?, ?), (?, ?), (?, ?), (?, ?)
+ (? /* SQL in Action */, ? /* 1 */),
+ (? /* SQL in Action */, ? /* 2 */),
+ (? /* Java in Action */, ? /* 1 */),
+ (? /* Java in Action */, ? /* 2 */)
)
```
@@ -823,6 +826,248 @@ where (tb_1_.NAME, tb_1_.EDITION) in (
这部分内容会在[子查询](../query/sub-query)相关文档中详细介绍,本文不做重复介绍。
:::
+### 优化
+
+Jimmer为`in list`表达式提供了3个优化:
+
+- 单值优化
+- Padding优化
+- Any等式优化
+
+1. 单值优化
+
+ 当列表长度为1时,`in(?)`会被自动改写为`= ?`,而`not in(?)`自动改写为`<> ?`,例如
+
+
+
+
+ ```java
+ where(
+ Expression.tuple(
+ book.name(),
+ book.edition()
+ ).in(
+ Arrays.asList(
+ new Tuple2<>("SQL in Action", 1)
+ )
+ )
+ );
+ ```
+
+
+
+
+ ```kotlin
+ where(
+ tuple(
+ table.name,
+ table.edition
+ ) valueIn listOf(
+ Tuple2("SQL in Action", 1)
+ )
+ )
+ ```
+
+
+
+
+ 生成的SQL条件
+ ```sql
+ where
+ (tb_1_.NAME, tb_1_.EDITION) =
+ (? /* SQL in Action */, ? /* 1 */)
+ ```
+
+2. Padding优化
+
+ 为了支持padding优化,Jimmer提供了开关,有如下两种开启方式
+
+ - 如果使用了Jimmer的Spring Boot Starter,修改`application.yml` *(或`application.properties`)*如下
+
+ ```sh title="application.yml"
+ jimmer:
+ #highlight-next-line
+ in-list-padding-enabled: true
+ ```
+
+ - 如果没有使用了Jimmer的Spring Boot Starter,则需要在创建`sqlClient`时调用如下API
+
+
+
+
+ ```java
+ JSqlClient sqlClient = JSqlClient
+ .newBuilder()
+ // highlight-next-line
+ .setInListPaddingEnabled(true)
+ // ...省略其他配置...
+ .build();
+ ```
+
+
+
+
+ ```kotlin
+ val sqlClient = newKSqlClient {
+ // highlight-next-line
+ setInListPaddingEnabled(true)
+ // ...省略其他配置...
+ }
+ ```
+
+
+
+
+ 一旦开启了此开关,Jimmer会保证列表的长度为2的幂次方 *(2,4,6,8,16,32,...)*,以此大幅降低SQL的多样性,提高数据库执行计划缓存的多样性。例如
+
+
+
+
+ ```java
+ where(
+ Expression.tuple(
+ book.name(),
+ book.edition()
+ ).in(
+ Arrays.asList(
+ new Tuple2<>("SQL in Action", 1),
+ new Tuple2<>("SQL in Action", 2),
+ new Tuple2<>("Java in Action", 1)
+ )
+ )
+ );
+ ```
+
+
+
+
+ ```kotlin
+ where(
+ tuple(
+ table.name,
+ table.edition
+ ) valueIn listOf(
+ Tuple2("SQL in Action", 1),
+ Tuple2("SQL in Action", 2),
+ Tuple2("Java in Action", 1)
+ )
+ )
+ ```
+
+
+
+
+ 此例子中,列表长度为3,并非2的幂次方。离3最近的2的幂次方是4,所以,Jimmer会重复列表中最后一项,最终让列表长度为4。生成的如下SQL条件
+
+ ```sql
+ where (tb_1_.NAME, tb_1_.EDITION) in (
+
+ // 原始列表
+ (? /* SQL in Action */, ? /* 1 */),
+ (? /* SQL in Action */, ? /* 2 */),
+ (? /* Java in Action */, ? /* 1 */),
+
+ // 重复原列表最后一项,让列表的长度为2的幂次方
+ // highlight-next-line
+ (? /* Java in Action */, ? /* 1 */)
+ )
+ ```
+
+3. Any等式优化
+
+ 该优化被前面讨论过的padding优化更为测试,但是存在两个限制
+
+ - 目前,只能优化单列in
+
+ - 数据库需支持`= any(?)`表达式,即`org.babyfish.jimmer.sql.dialect.Dialect`的实现类的`isAnyEqualityOfArraySupported()`方法需要返回true
+
+ > 当前,支持该行为的方言有
+ >
+ > - org.babyfish.jimmer.sql.dialect.H2Dialect
+ > - org.babyfish.jimmer.sql.dialect.PostgresDialect
+
+ 对此,Jimmer提供了开关,有如下两种开启方式
+
+ - 如果使用了Jimmer的Spring Boot Starter,修改`application.yml` *(或`application.properties`)*如下
+
+ ```sh title="application.yml"
+ jimmer:
+ #highlight-next-line
+ in-list-to-any-equality-enabled: true
+ ```
+
+ - 如果没有使用了Jimmer的Spring Boot Starter,则需要在创建`sqlClient`时调用如下API
+
+
+
+
+ ```java
+ JSqlClient sqlClient = JSqlClient
+ .newBuilder()
+ // highlight-next-line
+ .setInListToAnyEqualityEnabled(true)
+ // ...省略其他配置...
+ .build();
+ ```
+
+
+
+
+ ```kotlin
+ val sqlClient = newKSqlClient {
+ // highlight-next-line
+ setInListToAnyEqualityEnabled(true)
+ // ...省略其他配置...
+ }
+ ```
+
+
+
+
+ :::warning
+ 如果当前`org.babyfish.jimmer.sql.dialect.Dialect`实现类的`isAnyEqualityOfArraySupported()`方法返回false *(不支持此特性)*,
+ 此配置将会导致异常,`sqlClient`无法创建,应用无法启动。
+ :::
+
+
+
+
+ ```java
+ where(
+ book.name().in(
+ Arrays.asList(
+ "SQL in Action",
+ "Java in Action"
+ )
+ )
+ );
+ ```
+
+
+
+
+ ```kotlin
+ where(
+ table.name valueIn listOf(
+ "SQL in Action",
+ "Java in Action"
+ )
+ )
+ ```
+
+
+
+
+ 生成的SQL条件
+
+ ```sql
+ where tb_1_.NAME = any(
+ ? /* [SQL in Action, Java in Action] */
+ )
+ ```
+
+ 这里,整个list被视为一个整体,作为一个array类型的参数。
+
## 与、或、非
### 与
diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/quick-view/get-started/create-project.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/quick-view/get-started/create-project.mdx
index 1b8822b70..81913c551 100644
--- a/i18n/zh/docusaurus-plugin-content-docs/current/quick-view/get-started/create-project.mdx
+++ b/i18n/zh/docusaurus-plugin-content-docs/current/quick-view/get-started/create-project.mdx
@@ -57,7 +57,7 @@ Jimmer本身是高度中立的,可以脱离spring-boot使用;但同时也提
```xml title="pom.xml"
- 0.8.115
+ 0.8.130
@@ -75,7 +75,7 @@ Jimmer本身是高度中立的,可以脱离spring-boot使用;但同时也提
```groovy title="build.gradle"
ext {
- jimmerVersion = "0.8.115"
+ jimmerVersion = "0.8.130"
}
dependencies {
@@ -90,7 +90,7 @@ dependencies {
```kotlin title="build.gradle.kts"
-val jimmerVersion = "0.8.115"
+val jimmerVersion = "0.8.130"
dependencies {
@@ -114,7 +114,7 @@ plugins {
jimmer {
// 设定 jimmer 依赖版本,此处也可以使用 "latest.release" 或 "0.+" 等版本范围表达式
- version = "0.8.115"
+ version = "0.8.130"
}
```
@@ -132,7 +132,7 @@ plugins {
jimmer {
// 设定 jimmer 依赖版本,此处也可以使用 "latest.release" 或 "0.+" 等版本范围表达式
- version = "0.8.115"
+ version = "0.8.130"
}
```
diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/showcase/where/dynamic-join.mdx b/i18n/zh/docusaurus-plugin-content-docs/current/showcase/where/dynamic-join.mdx
index 2481abbce..620456b4b 100644
--- a/i18n/zh/docusaurus-plugin-content-docs/current/showcase/where/dynamic-join.mdx
+++ b/i18n/zh/docusaurus-plugin-content-docs/current/showcase/where/dynamic-join.mdx
@@ -124,7 +124,7 @@ where
类似Java中`table.store()`或Kotlin`table.store`这样的连接路径,会被渲染成SQL的内连接,而非外连接,这是因为
:::info
-内连接比外链接拥有更好的性能!
+内连接比外连接拥有更好的性能!
:::
:::caution
diff --git a/package.json b/package.json
index 309507705..4e50ba82c 100644
--- a/package.json
+++ b/package.json
@@ -15,8 +15,8 @@
"typecheck": "tsc"
},
"dependencies": {
- "@docusaurus/core": "^3.1.1",
- "@docusaurus/preset-classic": "^3.1.1",
+ "@docusaurus/core": "^3.3.2",
+ "@docusaurus/preset-classic": "^3.3.2",
"@easyops-cn/docusaurus-search-local": "^0.33.6",
"@emotion/react": "^11.9.3",
"@emotion/styled": "^11.9.3",
@@ -33,7 +33,7 @@
"use-immer": "^0.9.0"
},
"devDependencies": {
- "@docusaurus/module-type-aliases": "^2.1.0",
+ "@docusaurus/module-type-aliases": "^3.3.2",
"@tsconfig/docusaurus": "^1.0.5",
"babel-plugin-import": "^1.13.8",
"typescript": "^4.6.4"