无法在 sqlite 中使用 UUID id 保存聚合根
Unable to save aggregate root with UUID id in sqlite
在我的项目中,我有以下可以成功保存在 Postgres 中的实体:
public class Aggregate {
@Id
private UUID id;
private JsonNode data;
// getters and setters omitted
}
当我尝试在 SQLite 中保存相同的实体时,出现以下异常:
org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.Integer] to type [java.util.UUID]
at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:322) ~[spring-core-5.3.5.jar:5.3.5]
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:195) ~[spring-core-5.3.5.jar:5.3.5]
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:175) ~[spring-core-5.3.5.jar:5.3.5]
at org.springframework.data.mapping.model.ConvertingPropertyAccessor.convertIfNecessary(ConvertingPropertyAccessor.java:120) ~[spring-data-commons-2.4.6.jar:2.4.6]
at org.springframework.data.mapping.model.ConvertingPropertyAccessor.setProperty(ConvertingPropertyAccessor.java:63) ~[spring-data-commons-2.4.6.jar:2.4.6]
at org.springframework.data.jdbc.core.JdbcAggregateChangeExecutionContext.setIdAndCascadingProperties(JdbcAggregateChangeExecutionContext.java:337) ~[spring-data-jdbc-2.1.6.jar:2.1.6]
at org.springframework.data.jdbc.core.JdbcAggregateChangeExecutionContext.populateIdsIfNecessary(JdbcAggregateChangeExecutionContext.java:305) ~[spring-data-jdbc-2.1.6.jar:2.1.6]
at org.springframework.data.jdbc.core.AggregateChangeExecutor.execute(AggregateChangeExecutor.java:52) ~[spring-data-jdbc-2.1.6.jar:2.1.6]
at org.springframework.data.jdbc.core.JdbcAggregateTemplate.store(JdbcAggregateTemplate.java:339) ~[spring-data-jdbc-2.1.6.jar:2.1.6]
at org.springframework.data.jdbc.core.JdbcAggregateTemplate.save(JdbcAggregateTemplate.java:149) ~[spring-data-jdbc-2.1.6.jar:2.1.6]
at org.springframework.data.jdbc.repository.support.SimpleJdbcRepository.save(SimpleJdbcRepository.java:60) ~[spring-data-jdbc-2.1.6.jar:2.1.6]
Table SQLite 的定义:
create table aggregate
(
id text primary key,
data text not null
);
出于某种原因 Spring 数据 JDBC 尝试在聚合中设置整数类型的 id,尽管它 a) 是另一种类型并且 b) 已经存在。我尝试了不同的 IdGenerator
,在 table 定义中使用 without rowid
但没有任何改变。
我正在使用 Spring 数据 JDBC 2.1.6 和 xerial/sqlite-jdbc 3.34.0。
我该如何解决这个问题?
更新以回答 Jens Schauder 的问题:我忘了提及适当设置 UUID 的回调。我还有两个转换器可以在 JsonNode
和 PGobject
之间进行转换(此处未显示)。
@Component
public class AggregateCallback implements BeforeConvertCallback<Aggregate> {
@Override
public Aggregate onBeforeConvert(final Aggregate aggregate) {
if (aggregate.getId() == null) {
aggregate.setId(UUID.randomUUID());
}
return aggregate;
}
}
无论是哪个数据库,都会调用 AggregateCallback
,但使用 SQLite 时会抛出异常 在 执行回调后。
按照 Jens Schauder 在评论中的建议切换到 Spring Data 2021.0.0-M5 解决了问题!
正如@tammOr 在 Spring Data 2021.0.0-M5 修复问题后使用版本回答的那样。
以下是原因和方式的解释。
当 Spring 数据 JDBC 保存聚合时,它在旧版本中执行以下操作:
判断聚合是否是新的。有多种方法可以做到这一点,但这里适用的情况是检查 id,如果它是空的(null
对于对象类型或 0
对于数字基元。
因为 id 是 null
,它决定聚合是新的并且需要 INSERT
。在执行之前,它会触发@tammOr 用来设置 id 的一些事件。
然后执行插入
由于默认策略是在数据库中生成id,插入后会尝试从JDBC驱动中获取生成的id。出于某种原因,SQLite 驱动程序实际上 returns 一个 Integer
类型的值。
Spring 数据 JDBC 然后尝试将其转换为 UUID
但失败了。
使用更高版本Spring 数据JDBC 意识到它在步骤 4 中已经有一个 ID,并且不会向驱动程序询问生成的 ID,并跳过步骤 5,所以一切都很开心。
这是解决问题的拉取请求:https://github.com/spring-projects/spring-data-jdbc/pull/939
在我的项目中,我有以下可以成功保存在 Postgres 中的实体:
public class Aggregate {
@Id
private UUID id;
private JsonNode data;
// getters and setters omitted
}
当我尝试在 SQLite 中保存相同的实体时,出现以下异常:
org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.Integer] to type [java.util.UUID]
at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:322) ~[spring-core-5.3.5.jar:5.3.5]
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:195) ~[spring-core-5.3.5.jar:5.3.5]
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:175) ~[spring-core-5.3.5.jar:5.3.5]
at org.springframework.data.mapping.model.ConvertingPropertyAccessor.convertIfNecessary(ConvertingPropertyAccessor.java:120) ~[spring-data-commons-2.4.6.jar:2.4.6]
at org.springframework.data.mapping.model.ConvertingPropertyAccessor.setProperty(ConvertingPropertyAccessor.java:63) ~[spring-data-commons-2.4.6.jar:2.4.6]
at org.springframework.data.jdbc.core.JdbcAggregateChangeExecutionContext.setIdAndCascadingProperties(JdbcAggregateChangeExecutionContext.java:337) ~[spring-data-jdbc-2.1.6.jar:2.1.6]
at org.springframework.data.jdbc.core.JdbcAggregateChangeExecutionContext.populateIdsIfNecessary(JdbcAggregateChangeExecutionContext.java:305) ~[spring-data-jdbc-2.1.6.jar:2.1.6]
at org.springframework.data.jdbc.core.AggregateChangeExecutor.execute(AggregateChangeExecutor.java:52) ~[spring-data-jdbc-2.1.6.jar:2.1.6]
at org.springframework.data.jdbc.core.JdbcAggregateTemplate.store(JdbcAggregateTemplate.java:339) ~[spring-data-jdbc-2.1.6.jar:2.1.6]
at org.springframework.data.jdbc.core.JdbcAggregateTemplate.save(JdbcAggregateTemplate.java:149) ~[spring-data-jdbc-2.1.6.jar:2.1.6]
at org.springframework.data.jdbc.repository.support.SimpleJdbcRepository.save(SimpleJdbcRepository.java:60) ~[spring-data-jdbc-2.1.6.jar:2.1.6]
Table SQLite 的定义:
create table aggregate
(
id text primary key,
data text not null
);
出于某种原因 Spring 数据 JDBC 尝试在聚合中设置整数类型的 id,尽管它 a) 是另一种类型并且 b) 已经存在。我尝试了不同的 IdGenerator
,在 table 定义中使用 without rowid
但没有任何改变。
我正在使用 Spring 数据 JDBC 2.1.6 和 xerial/sqlite-jdbc 3.34.0。
我该如何解决这个问题?
更新以回答 Jens Schauder 的问题:我忘了提及适当设置 UUID 的回调。我还有两个转换器可以在 JsonNode
和 PGobject
之间进行转换(此处未显示)。
@Component
public class AggregateCallback implements BeforeConvertCallback<Aggregate> {
@Override
public Aggregate onBeforeConvert(final Aggregate aggregate) {
if (aggregate.getId() == null) {
aggregate.setId(UUID.randomUUID());
}
return aggregate;
}
}
无论是哪个数据库,都会调用 AggregateCallback
,但使用 SQLite 时会抛出异常 在 执行回调后。
按照 Jens Schauder 在评论中的建议切换到 Spring Data 2021.0.0-M5 解决了问题!
正如@tammOr 在 Spring Data 2021.0.0-M5 修复问题后使用版本回答的那样。 以下是原因和方式的解释。
当 Spring 数据 JDBC 保存聚合时,它在旧版本中执行以下操作:
判断聚合是否是新的。有多种方法可以做到这一点,但这里适用的情况是检查 id,如果它是空的(
null
对于对象类型或0
对于数字基元。因为 id 是
null
,它决定聚合是新的并且需要INSERT
。在执行之前,它会触发@tammOr 用来设置 id 的一些事件。然后执行插入
由于默认策略是在数据库中生成id,插入后会尝试从JDBC驱动中获取生成的id。出于某种原因,SQLite 驱动程序实际上 returns 一个
Integer
类型的值。Spring 数据 JDBC 然后尝试将其转换为
UUID
但失败了。
使用更高版本Spring 数据JDBC 意识到它在步骤 4 中已经有一个 ID,并且不会向驱动程序询问生成的 ID,并跳过步骤 5,所以一切都很开心。
这是解决问题的拉取请求:https://github.com/spring-projects/spring-data-jdbc/pull/939