【发布时间】:2020-12-12 02:55:00
【问题描述】:
问题:在聚合状态 Axon SpringBoot 应用程序中,@AggregateIdentifier 的类型为 UUID,而 PostgreSQL 数据库列的类型为 UUID。当在 create-commands 上持久化时 - 标识符已成功存储。当发送更新命令警告上升并且命令未传递到聚合处理程序时,因为@TargetAggregateIdentifier 需要字符串类型as described by Axon here:
java.lang.IllegalArgumentException:为 类 ....MyAggregate。预期:类 java.util.UUID,得到类 java.lang.String
研究:
-
工作解决方案是将域重构为所有聚合标识符的
String类型。数据库@Id字段也应转换为varchar(36)类型以存储UUID.toString()作为主键。主要的缺点是效率低下:9 倍的大小和更慢的字符串读取。 -
最小样板和折衷解决方案是将所有聚合标识符的域重构为
String类型,并使用javax.persistence.Converters在 JPA 层中将 String 转换为 UUID,同时保持:@Converter public class UuidJpaConverter implements AttributeConverter<String, UUID> { @Override public UUID convertToDatabaseColumn(String uuid) { return fromString(uuid); } @Override public String convertToEntityAttribute(UUID uuid) { return uuid.toString(); } } ... @Aggregate @Entity @IdClass(UuidKey.class) public class MyAggregate implements Serializable { @AggregateIdentifier @Id private String uuid; ... } public class UuidKey implements Serializable { @Column(name = "uuid", nullable = false, updatable = false) @Convert(converter = UuidJpaConverter.class) private String uuid; }
但结果是:
o.h.engine.jdbc.spi.SqlExceptionHelper:错误:列“uuid”的类型为 uuid,但表达式的类型为 bytea
-
使用 Axon 标识符转换器,但它需要为每个聚合自定义 GenericJpaRepository,实际上从不在断点上调用 identifierConverter 处理程序:
@Configuration public class IdentifierConverter { @Bean public GenericJpaRepository<MyAggregate> aggregateJpaRepository( EntityManagerProvider provider, @Qualifier("eventBus") EventBus simpleEventBus) { GenericJpaRepository<MyAggregate> repository = GenericJpaRepository .builder(MyAggregate.class) -> .identifierConverter(name -> UUID.fromString(name)) .entityManagerProvider(provider) .eventBus(simpleEventBus) .build(); return repository; } }
结果:
o.h.engine.jdbc.spi.SqlExceptionHelper:错误:列“uuid”属于 输入 uuid,但表达式的类型是不同的字符
-
还有一个suggested universal GenericJpaRepository solution 来查找聚合标识符的类型,并且 - 除非它已经是一个字符串 - 通过 Spring 转换服务对其进行转换。但是当我们有 Axon 自动配置并且期望 bean 支持 Configurer 时,不清楚在哪里绑定它会将它添加到配置器中的
registerAggregateBeanDefinitions:final Class<?> aggregateIdentifierType = Stream.of( aggregateType.getDeclaredFields( ) ) .filter( field -> field.isAnnotationPresent( AggregateIdentifier.class ) ) .map( field -> field.getType( ) ) .findFirst( ) .orElseThrow( ( ) -> new IllegalStateException( "The aggregate '" + aggregate + "' does not have an identifier." ) ); aggregateConf.configureRepository( c -> GenericJpaRepository.builder( aggregateType ) .identifierConverter( string -> { if ( aggregateType == String.class ) { return string; } else { try { final ConversionService conversionService = beanFactory.getBean( ConversionService.class ); return conversionService.convert( string, aggregateIdentifierType ); } catch ( final NoSuchBeanDefinitionException ex ) { throw new IllegalStateException( "Unable to convert String to aggregate identifier of type '" + aggregateIdentifierType.getName( ) + "'. A conversion service is missing." ); } } } ) ... @Named final class MyIdConverter implements Converter<String, MyId> { ... @Override public MyId convert( final String source ) { return MyId.fromString( source ); } }
问题:如何在 PostgreSQL 数据库中保留 UUID 类型的聚合标识符 - 将 UUID 作为 @AggregateIdentifier 或至少 String 的首选类型。另外,如果at 2010 UUID was widely used in Axon,为什么目前只支持String?
【问题讨论】:
标签: java postgresql spring-boot jpa axon