Search code examples
javacassandradatastax-java-driver

I have declared primary using PartitionKey annotation but still getting Entity Order does not declare a primary key


I have the following POJO:

@Entity
public class Order {    
    
    @Column(name = "id")
    @PartitionKey
    private String id;

    @Column(name = "customer_id")
    private String customerId;

    @Column(name = "loyalty_id")
    private String loyaltyId;

    @Column(name = "customer_email")
    private String customerEmail;

    public Order() {

    }
    public String getId() {
       return id;
    }

    public void setId(String id) {
        this.id = id;
    }
    ... getters and setters
}

Getting the exception at the following code:

            CqlSession session = CqlSession.builder().build();
            OrderMapper mapper = new OrderMapperBuilder(session).build();
            orderDao = mapper.orderDao(CqlIdentifier.fromCql(connectionManager.getSession().getLoggedKeyspace()));

The definition of connectionManager is here: https://pastebin.com/b3GKJuV6

The exception is as:

    Entity Order does not declare a primary key
    com.datastax.oss.driver.api.mapper.MapperException: Entity Order does not declare a primary key
        at com.datastax.oss.driver.api.mapper.MapperException.copy(MapperException.java:44)
        at com.datastax.oss.driver.internal.core.util.concurrent.CompletableFutures.getUninterruptibly(CompletableFutures.java:149)
    ...

I am implementing by following the documentation here: https://docs.datastax.com/en/developer/java-driver/4.2/manual/mapper/ . What could be the possible cause of this?

EDIT:- Adding the schema definition:

    CREATE TABLE order_keyspace.order (
        id text PRIMARY KEY,
        customer_email text,
        customer_id text,
        loyalty_id text
    ) WITH bloom_filter_fp_chance = 0.01
        AND caching = {'keys': 'ALL', 'rows_per_partition': 'NONE'}
        AND comment = ''
        AND compaction = {'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy', 'max_threshold': '32', 'min_threshold': '4'}
        AND compression = {'chunk_length_in_kb': '64', 'class': 'org.apache.cassandra.io.compress.LZ4Compressor'}
        AND crc_check_chance = 1.0
        AND dclocal_read_repair_chance = 0.1
        AND default_time_to_live = 0
        AND gc_grace_seconds = 864000
        AND max_index_interval = 2048
        AND memtable_flush_period_in_ms = 0
        AND min_index_interval = 128
        AND read_repair_chance = 0.0
        AND speculative_retry = '99PERCENTILE';

Solution

  • Full Edit :

    There are a few things going on here which confuses me, and the only way I could reproduce the error was to break the getter/setter which doesn't appear to be wrong on your code, but there is some copy/paste conversions that are happening. What I can so far see as follows:

    • The use of @Column(name = "id") - which is not an annotation from com.datastax.oss.driver.api.mapper.annotations. @CqlName should be used.
    • The use of a reserved keyword for a table - the term 'order' is a reserved keyword, I am pretty sure this results in considerable confusion within the code - although I got a different error when I attempted to use the keyword as a table name with the mapper. I think you should name this table to something else and avoid the keyword.

    Annotation Link: https://docs.datastax.com/en/developer/java-driver/4.2/manual/mapper/entities/ contains the rules / annotations available and you can see the use of @CqlName there to inform the mapper of the Cassandra column name if it differs from the naming convention.

    I belive you were on the 4.2 driver in an earlier question - but if updated to 4.7 (recommended) then this is the link : https://docs.datastax.com/en/developer/java-driver/4.7/manual/mapper/entities/ )

    The following code worked correctly:

    Cql:

    CREATE TABLE customer_orders (
        id text PRIMARY KEY,
        customer_email text,
        customer_id text,
        loyalty_id text
    );
    
    insert into customer_orders (id, customer_email, customer_id, loyalty_id) values ('a','a@b.c.com', '1234', '5678');
    

    Pojo:

    import com.datastax.oss.driver.api.mapper.annotations.CqlName;
    import com.datastax.oss.driver.api.mapper.annotations.Entity;
    import com.datastax.oss.driver.api.mapper.annotations.PartitionKey;
    
    @Entity
    public class CustomerOrders {
        @CqlName("id")
        @PartitionKey
        private String id;
    
        @CqlName("customer_id")
        private String customerId;
    
        @CqlName("loyalty_id")
        private String loyaltyId;
    
        @CqlName("customer_email")
        private String customerEmail;
    
        public CustomerOrders() {
    
        }
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    
        public String getCustomerId() {
            return customerId;
        }
    
        public void setCustomerId(String customerId) {
            this.customerId = customerId;
        }
    
        public String getLoyaltyId() {
            return loyaltyId;
        }
    
        public void setLoyaltyId(String loyaltyId) {
            this.loyaltyId = loyaltyId;
        }
    
        public String getCustomerEmail() {
            return customerEmail;
        }
    
        public void setCustomerEmail(String customerEmail) {
            this.customerEmail = customerEmail;
        }
    }
    

    DaoMapper:

    import com.datastax.oss.driver.api.core.CqlIdentifier;
    import com.datastax.oss.driver.api.mapper.annotations.*;
    
    @Mapper
    public interface DaoMapper {
    
        @DaoFactory
        OrderDao orderDao(@DaoKeyspace CqlIdentifier keyspace);
    }
    

    OrderDao:

    import com.datastax.oss.driver.api.mapper.annotations.Dao;
    import com.datastax.oss.driver.api.mapper.annotations.Delete;
    import com.datastax.oss.driver.api.mapper.annotations.Insert;
    import com.datastax.oss.driver.api.mapper.annotations.Select;
    
    @Dao
    public interface OrderDao {
    
        @Select
        CustomerOrders findById(String id);
    
        @Insert
        void save(CustomerOrders order);
    
        @Delete
        void delete(CustomerOrders order);
    }
    

    I then created a simple test snippet:

     @Test
        void GetRecordViaOrderDao() {
            try (CqlSession session = CqlSession.builder().build()) {
    
                DaoMapper daoMapper = new DaoMapperBuilder(session).build();
                OrderDao orderDao = daoMapper.orderDao(CqlIdentifier.fromCql("killrvideo"));
                CustomerOrders order = orderDao.findById("a");
                System.out.println(order.getCustomerEmail());
            }
        }
    

    killrvideo keyspace in this instance because I am hitting an Astra DB and thats the keyspace I have there currently.

    Result: a@b.c.com
    

    Driver version 4.7.2 was specified in my pom.xml