Spring Data cassandra 抛出:无法获取实体的 where 子句
Spring Data cassandra throws: Cannot obtain where clauses for entity
我正在尝试使用 Spring data cassandra 通过 REST api 与 cassandra/scyllaDB 通信。
我有实体
@Table
public class Transaction {
@PrimaryKeyColumn(name = "id", ordinal = 0, type = PrimaryKeyType.PARTITIONED)
private String id;
@PrimaryKeyColumn(name = "timestamp", ordinal = 1, type = PrimaryKeyType.CLUSTERED)
private Instant timestamp;
private String currency;
}
有存储库
@Repository
public interface TransactionRepository extends CassandraRepository<Transaction, String> {
}
和在 REST 控制器中调用的服务
@Service
public class TransactionServiceImpl implements TransactionService{
@Autowired
private TransactionRepository transactionRepository;
private Transaction getTransaction(String transactionId) {
return transactionRepository.findById(transactionId)
.orElseThrow(() -> new NotFoundException("Transaction with provided " + transactionId + " does not exist."));
}
}
当我调用所需的 REST 端点时,我提供了正确的 transactionId,抛出异常。
Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: Cannot obtain where clauses for
entity [com.example.dao.entity.Transaction] using [id123456]
我做了一些调查,但实体 class 中提供的组合键应该是有效的。我做错了什么?
table 型号:
CREATE TABLE etl.transaction
(
id text,
timestamp timestamp,
currency ascii,
PRIMARY KEY (id, timestamp)
)
WITH CLUSTERING ORDER BY (timestamp ASC) AND
default_time_to_live = 157680000; // 5 years in seconds
我从未收到此错误消息。如果您有 setter/getter 方法或使用 Lombok 项目并在 @Table 旁边添加 @Data 注释,您会收到什么错误消息? (如果你使用IntelliJ,你必须安装Lombok插件!)
在我的回答中,如果有任何结果,请发表评论。
@Data
@Table
public class Transaction {
@PrimaryKeyColumn(name = "id", ordinal = 0, type = PrimaryKeyType.PARTITIONED)
private String id;
@PrimaryKeyColumn(name = "timestamp", ordinal = 1, type = PrimaryKeyType.CLUSTERED)
private Instant timestamp;
private String currency;
}
更新
TL;DR:如果只有一个@PrimaryKeyColumn,只需在属性上方添加@Id。如果你使用更多的@PrimaryKeyColumn,你必须使用:
- @PrimaryKey 和@PrimaryKeyClass(您可以使用 findById)
public interface TestRepository extends CassandraRepository<Test, KeyClass> {
}
@Data
@Table
public class Test {
@PrimaryKey
private KeyClass id;
@Data
@PrimaryKeyClass
public static class KeyClass { // You either give it a different name or move it in another file. Nevermind.
@PrimaryKeyColumn(name = "id", type = PrimaryKeyType.PARTITIONED)
private Integer id;
@PrimaryKeyColumn(name = "data")
private Integer data;
}
}
- 或下一个接口:
public interface TestRepository extends CassandraRepository<Test, Integer> {
Optional<Test> findByIdAndData(Integer id, Integer data);
}
@Data
@Table
public class Test {
@PrimaryKeyColumn(name = "id", type = PrimaryKeyType.PARTITIONED)
private Integer id;
@PrimaryKeyColumn(name = "data")
private Integer data;
}
独奏@PrimaryKeyColumn
测试数据:
-- auto-generated definition
CREATE TABLE test
(
id int PRIMARY KEY,
data int
)
WITH CACHING = {'keys': 'ALL', 'rows_per_partition': 'NONE'}
AND COMPACTION = {'max_threshold': '32', 'min_threshold': '4', 'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy'}
AND COMPRESSION = {'class': 'org.apache.cassandra.io.compress.LZ4Compressor', 'chunk_length_in_kb': '64'}
AND DCLOCAL_READ_REPAIR_CHANCE = 0.1;
public interface TestRepository extends CassandraRepository<Test, Integer> {
}
@Data
@Table
public class Test {
/*
* You can only use "findById" or "findallById" with @Id annotation.
* @PrimaryKey contains the @Id itself, but ofc you have to configuration @PrimaryKeyClass.
*/
@PrimaryKeyColumn(name = "id", type = PrimaryKeyType.PARTITIONED)
@Id // <-- add
private Integer id;
@Column("data")
private Integer data;
}
测试:
@SpringBootTest
class ApplicationTests {
@Autowired
private TestRepository testRepository;
@Test
void contextLoads() {
var x = testRepository.findById(1).orElse(null);
if(x == null) {
fail();
}
assertEquals((int) x.getData(), 5);
}
}
结果:
带@PrimaryKey
Table:
public interface TestRepository extends CassandraRepository<Test, KeyClass> {
}
@Data
@Table
public class Test {
@PrimaryKey
private KeyClass id;
@Data
@PrimaryKeyClass
public static class KeyClass { // You either give it a different name or move it in another file. Nevermind.
@PrimaryKeyColumn(name = "id", type = PrimaryKeyType.PARTITIONED)
private Integer id;
@PrimaryKeyColumn(name = "data")
private Integer data;
}
}
使用 JPA API
第二种遗传类型(定义什么类型的id)无所谓,在这个解决方案上。
如果您只想按分区查询。 CLUSTERED 存在!
方案一:
第二种遗传类型(定义什么类型的id)无所谓,在这个解决方案上。
方案二:
将 id
重命名为其他名称并以这种方式配置 JPA。
第二种遗传类型(定义什么类型的id)无所谓,在这个解决方案上。
@PrimaryKeyClass 的解决方案
public interface TestRepository extends CassandraRepository<Test, KeyClass> {
// findby[ID-1]_[ID-2](...)
// ID-1 is mean: Test's "id" attribute
// "_" is mean chain/access instance
// ID-2 is mean: KeyClass's "id" attribute
Optional<Test> findById_Id(Integer id);
// Look this both:
Optional<Test> findById_IdAndId_Data(Integer id, Integer data);
}
我正在尝试使用 Spring data cassandra 通过 REST api 与 cassandra/scyllaDB 通信。 我有实体
@Table
public class Transaction {
@PrimaryKeyColumn(name = "id", ordinal = 0, type = PrimaryKeyType.PARTITIONED)
private String id;
@PrimaryKeyColumn(name = "timestamp", ordinal = 1, type = PrimaryKeyType.CLUSTERED)
private Instant timestamp;
private String currency;
}
有存储库
@Repository
public interface TransactionRepository extends CassandraRepository<Transaction, String> {
}
和在 REST 控制器中调用的服务
@Service
public class TransactionServiceImpl implements TransactionService{
@Autowired
private TransactionRepository transactionRepository;
private Transaction getTransaction(String transactionId) {
return transactionRepository.findById(transactionId)
.orElseThrow(() -> new NotFoundException("Transaction with provided " + transactionId + " does not exist."));
}
}
当我调用所需的 REST 端点时,我提供了正确的 transactionId,抛出异常。
Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: Cannot obtain where clauses for
entity [com.example.dao.entity.Transaction] using [id123456]
我做了一些调查,但实体 class 中提供的组合键应该是有效的。我做错了什么?
table 型号:
CREATE TABLE etl.transaction
(
id text,
timestamp timestamp,
currency ascii,
PRIMARY KEY (id, timestamp)
)
WITH CLUSTERING ORDER BY (timestamp ASC) AND
default_time_to_live = 157680000; // 5 years in seconds
我从未收到此错误消息。如果您有 setter/getter 方法或使用 Lombok 项目并在 @Table 旁边添加 @Data 注释,您会收到什么错误消息? (如果你使用IntelliJ,你必须安装Lombok插件!)
在我的回答中,如果有任何结果,请发表评论。
@Data
@Table
public class Transaction {
@PrimaryKeyColumn(name = "id", ordinal = 0, type = PrimaryKeyType.PARTITIONED)
private String id;
@PrimaryKeyColumn(name = "timestamp", ordinal = 1, type = PrimaryKeyType.CLUSTERED)
private Instant timestamp;
private String currency;
}
更新
TL;DR:如果只有一个@PrimaryKeyColumn,只需在属性上方添加@Id。如果你使用更多的@PrimaryKeyColumn,你必须使用:
- @PrimaryKey 和@PrimaryKeyClass(您可以使用 findById)
public interface TestRepository extends CassandraRepository<Test, KeyClass> {
}
@Data
@Table
public class Test {
@PrimaryKey
private KeyClass id;
@Data
@PrimaryKeyClass
public static class KeyClass { // You either give it a different name or move it in another file. Nevermind.
@PrimaryKeyColumn(name = "id", type = PrimaryKeyType.PARTITIONED)
private Integer id;
@PrimaryKeyColumn(name = "data")
private Integer data;
}
}
- 或下一个接口:
public interface TestRepository extends CassandraRepository<Test, Integer> {
Optional<Test> findByIdAndData(Integer id, Integer data);
}
@Data
@Table
public class Test {
@PrimaryKeyColumn(name = "id", type = PrimaryKeyType.PARTITIONED)
private Integer id;
@PrimaryKeyColumn(name = "data")
private Integer data;
}
独奏@PrimaryKeyColumn
测试数据:
-- auto-generated definition
CREATE TABLE test
(
id int PRIMARY KEY,
data int
)
WITH CACHING = {'keys': 'ALL', 'rows_per_partition': 'NONE'}
AND COMPACTION = {'max_threshold': '32', 'min_threshold': '4', 'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy'}
AND COMPRESSION = {'class': 'org.apache.cassandra.io.compress.LZ4Compressor', 'chunk_length_in_kb': '64'}
AND DCLOCAL_READ_REPAIR_CHANCE = 0.1;
public interface TestRepository extends CassandraRepository<Test, Integer> {
}
@Data
@Table
public class Test {
/*
* You can only use "findById" or "findallById" with @Id annotation.
* @PrimaryKey contains the @Id itself, but ofc you have to configuration @PrimaryKeyClass.
*/
@PrimaryKeyColumn(name = "id", type = PrimaryKeyType.PARTITIONED)
@Id // <-- add
private Integer id;
@Column("data")
private Integer data;
}
测试:
@SpringBootTest
class ApplicationTests {
@Autowired
private TestRepository testRepository;
@Test
void contextLoads() {
var x = testRepository.findById(1).orElse(null);
if(x == null) {
fail();
}
assertEquals((int) x.getData(), 5);
}
}
结果:
带@PrimaryKey
Table:
public interface TestRepository extends CassandraRepository<Test, KeyClass> {
}
@Data
@Table
public class Test {
@PrimaryKey
private KeyClass id;
@Data
@PrimaryKeyClass
public static class KeyClass { // You either give it a different name or move it in another file. Nevermind.
@PrimaryKeyColumn(name = "id", type = PrimaryKeyType.PARTITIONED)
private Integer id;
@PrimaryKeyColumn(name = "data")
private Integer data;
}
}
使用 JPA API
第二种遗传类型(定义什么类型的id)无所谓,在这个解决方案上。
如果您只想按分区查询。 CLUSTERED 存在!
方案一:
第二种遗传类型(定义什么类型的id)无所谓,在这个解决方案上。
方案二:
将 id
重命名为其他名称并以这种方式配置 JPA。
第二种遗传类型(定义什么类型的id)无所谓,在这个解决方案上。
@PrimaryKeyClass 的解决方案
public interface TestRepository extends CassandraRepository<Test, KeyClass> {
// findby[ID-1]_[ID-2](...)
// ID-1 is mean: Test's "id" attribute
// "_" is mean chain/access instance
// ID-2 is mean: KeyClass's "id" attribute
Optional<Test> findById_Id(Integer id);
// Look this both:
Optional<Test> findById_IdAndId_Data(Integer id, Integer data);
}