如何使用 Spring Data Cassandra 将用户定义类型的集合保存到 ScyllaDB?

How to save collection of user defined type to ScyllaDB with Spring Data Cassandra?

当我尝试使用列表或用户定义类型集保存实体时,出现错误:

Failed to convert from type [java.util.ImmutableCollections$Set12<?>] to type [com.datastax.oss.driver.api.core.data.UdtValue] for value '[scrubbed.entity.Article$AttachmentInfo@3337c2b5]'; nested exception is org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [scrubbed.entity.Article$AttachmentInfo] to type [com.datastax.oss.driver.api.core.data.UdtValue]]

这是 ScyllaDB 数据库中的定义:

CREATE TYPE IF NOT EXISTS attachment_info (
  id        UUID,
  fileName  TEXT,
  mimeType  TEXT,
  sizeBytes BIGINT
);

CREATE TABLE IF NOT EXISTS articles
(
  id          UUID,
  attachments SET<frozen<attachment_info>>,
  PRIMARY KEY (id)
);

Java 中的实体:

@Getter
@Setter
@Table("articles")
@NoArgsConstructor
@AllArgsConstructor
@Builder(toBuilder = true)
public class Article {

  @PrimaryKeyColumn(name = "id", ordinal = 0, type = PrimaryKeyType.PARTITIONED)
  private UUID id;

  @Column("attachments")
  @CassandraType(type = CassandraType.Name.UDT, userTypeName = "attachment_info")
  private Set<AttachmentInfo> attachments = new HashSet<>();

  @Getter
  @Setter
  @NoArgsConstructor
  @AllArgsConstructor
  @UserDefinedType("attachment_info")
  public static class AttachmentInfo {
    private UUID id;
    private String fileName;
    private String mimeType;
    private Long sizeBytes;
  }
}

并保存到数据库:

var metadata = new Article.AttachmentInfo();
metadata.setFileName("Filename");
metadata.setId(UUID.randomUUID());
metadata.setMimeType("image/png");
metadata.setSizeBytes(12345L);

var article = new Article();
article.setId(UUID.randomUUID());
article.setAttachments(Set.of(metadata));
articleRepository.insert(article);

使用 spring-data-cassandra

3.2.0 版本

我不是 Spring 专家(只是 Scylla 专家 ;-)),所以如果我的回答不起作用,请原谅我。

在我看来注释

@Column("attachments")
@CassandraType(type = CassandraType.Name.UDT, userTypeName = "attachment_info")
  private Set<AttachmentInfo> attachments = new HashSet<>();

是错误的,因为它告诉 spring-data-cassandra“附件”列是一个 UDT,而实际上它不是 - 它是一组(UDT)。

我认为一组 UDT 的正确注释应该是这样的:

@CassandraType(type = DataType.Name.SET, typeArguments = DataType.Name.UDT)

但我不确定(我无法在文档中找到示例)将 userTypeName 放在哪里。如果我对文档的理解正确,则您不需要显式使用该 userTypeName,因为您使用 UserDefinedType 注释对 AttachmentInfo class 进行了注释,说明其 scylla 名称为“attachment_info”,这应该足够了。

此外,根据我阅读的一些文档,您可能根本不需要 attachements 上的 CassandraType 注释,因为 spring-data-cassandra 理解 Set<AttachmentInfo> 因为它知道原始类型 Set,并且您已经将 AttachmentInfo 注释为 UDT。