微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Spring Data Cassandra抛出:无法获取实体的where子句

如何解决Spring Data Cassandra抛出:无法获取实体的where子句

iam尝试使用Spring数据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]

我进行了一些调查,但是实体类中提供的组合键应该有效。我在做什么错?

表的型号:

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一起

测试数据: enter image description here

-- 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);
    }
}

结果:enter image description here


使用@PrimaryKey 表格:enter image description here

public interface TestRepository extends CassandraRepository<Test,type = PrimaryKeyType.PARTITIONED)
        private Integer id;
    
        @PrimaryKeyColumn(name = "data")
        private Integer data;
    }
}

enter image description here


使用JPA API

在此解决方案上,第二种遗传类型(定义的id类型)无关紧要。

enter image description here

enter image description here

enter image description here


如果只想按PARTITION进行查询。集群存在!

解决方案1:

在此解决方案上,第二种遗传类型(定义的id类型)无关紧要。

enter image description here

解决方案2:

id重命名为其他名称,然后以这种方式配置JPA。

在此解决方案上,第二种遗传类型(定义的id类型)无关紧要。

enter image description here

enter image description here

enter image description here

使用@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);
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。