在 Spring Converter 中将 `null` 转换为某个值

nik*_*eee 7 java spring cql cassandra spring-data-cassandra

添加新列时,数据库 (Cassandra) 不允许指定默认值。因此null,每一行都有新的列。

现在,我们为实体添加了一个标志(将来可能会获得更多条目):

enum UsageFlag {
    OTHER,
    SPECIAL_VALUE,
}
Run Code Online (Sandbox Code Playgroud)

我们还添加了一个 ReadingConverter:

@ReadingConverter
public class UsageFlagReadingConverter implements Converter<String, UsageFlag> {
  @Nonnull
  @Override
  public UsageFlag convert(String source) {
    return source == null
        ? UsageFlag.OTHER
        : UsageFlag.valueOf(source);
  }
}
Run Code Online (Sandbox Code Playgroud)

它应该基本上把nullUsageFlag.OTHER在分析任何其他非空值作为枚举成员。

但是,这不起作用,因为根据 Spring 文档,只有在值不是时才会调用Converterconvert 方法。因此,如果该实体在数据库中,则该实体的字段仍然存在。如果(且仅当)有值时,它才能正常工作。由于整个列在创建时为空,这完全违背了. nullnullnullReadingConverter

Cassandra 似乎不支持为每一行设置一个值(如UPDATE foo SET flag='OTHER' WHERE True),所以这似乎是一个不错的选择。我们希望避免手动接触数据库中的每一行。

在这种情况下,我们有什么方法可以使用 Spring 来提供帮助吗?或者有没有办法使用 CQL 或 Cassandra 解决这个问题?

编辑:有关设置的更多上下文:

public interface FancyEntityRepository extends MapIdCassandraRepository<FancyEntity> {
}

public class FancyEntity {
    @PrimaryKeyColumn(name = "id", ordinal = 0, type = PrimaryKeyType.PARTITIONED)
    private string id;
    private UsageFlag usage;
    // other columns omitted
    // getters and setter omitted for this example
}

// Somewhere in a service: 
FancyEntity fe = fancyEntityRepository.findOne("1");
System.out.println(fe.getUsage());
Run Code Online (Sandbox Code Playgroud)

但我不认为转换器的行为是特定于 cassandra 的。

该表已创建,然后以这种方式更改:

CREATE TABLE FancyEntity (
    id TEXT,
    -- other columns omitted
    PRIMARY KEY (id)
);
ALTER TABLE FancyEntity ADD (
    usage TEXT
);
Run Code Online (Sandbox Code Playgroud)

关于 ALTER TABLE 的 Cassandra Docs和有关使用默认值更改表的相关 SO 问题。

Eri*_*rez 1

Cassandra 具有稀疏存储,这意味着如果未设置列(RDBMS 中的字段),它不会存储列。因此,说“新列是null”是不正确的。

如果您使用准备好的语句,则需要BoundStatement.unset()使用本机协议 v3 进行调用,以便不会为null值生成逻辑删除。

否则,可以不使用本机协议 v4(Cassandra 2.2 或更高版本)设置变量。干杯!