2

Below is our entity class


  @Entity(defaultKeyspace = CASSANDRA_KEYSPACE)
  @CqlName(CASSANDRA_TABLE)
  public static class Scientist implements Serializable {

    @CqlName("person_name")
    public String name;

    @Computed("writetime(person_name)")
    @CqlName("name_ts")
    public Long nameTs;

    @CqlName("person_id")
    @PartitionKey
    public Integer id;

    public Scientist() {}

    public Scientist(int id, String name) {
      super();
      this.id = id;
      this.name = name;
    }

    public Integer getId() {
      return id;
    }

    public void setId(Integer id) {
      this.id = id;
    }


    public String getName() {
      return name;
    }

    public void setName(String name) {
      this.name = name;
    }

    @Override
    public String toString() {
      return id + ":" + name;
    }

    @Override
    public boolean equals(@Nullable Object o) {
      if (this == o) {
        return true;
      }
      if (o == null || getClass() != o.getClass()) {
        return false;
      }
      Scientist scientist = (Scientist) o;
      return id.equals(scientist.id) && Objects.equal(name, scientist.name);
    }

    @Override
    public int hashCode() {
      return Objects.hashCode(name, id);
    }
  }

  @Dao
  public interface ScientistDao {
  @GetEntity
  MappedAsyncPagingIterable<Scientist> map(AsyncResultSet resultSet);

  @Delete
  CompletionStage<Void> deleteAsync(Scientist entity);

  @Insert
  CompletionStage<Void> saveAsync(Scientist entity);
}

The problem faced is, when the computed fields (in the above case writetime(person_name) )are not selected as part of the query, the mapping fails.

In 3.x driver: mapped fields that are not present in the ResultSet were ignored. link

In 4.x driver: for each entity field, the database table or UDT must contain a column with the corresponding name. link

Please suggest a possible solution/workaround where this computed field can be part of the query on a need basis and the mapping happens successfully without throwing IllegalArgumentException.

Edit:

scientist table schema

CREATE TABLE beam_ks.scientist (person_id int PRIMARY KEY,person_name text);

Below is the query tried:

   select person_id,writetime(person_name) as name_ts from beam_ks.scientist where person_id=10

Mapping of the resultset with @GetEntity fails with below error:

Caused by: java.lang.IllegalArgumentException: person_name is not a column in this row
    at com.datastax.oss.driver.internal.core.cql.DefaultRow.firstIndexOf(DefaultRow.java:110)
    at com.datastax.oss.driver.api.core.data.GettableByName.get(GettableByName.java:144)
    at org.apache.beam.sdk.io.cassandra.CassandraIOTest_ScientistHelper__MapperGenerated.get(CassandraIOTest_ScientistHelper__MapperGenerated.java:89)

get method in CassandraIOTest_ScientistHelper__MapperGenerated:

  @Override
  public CassandraIOTest.Scientist get(GettableByName source) {
    CassandraIOTest.Scientist returnValue = new CassandraIOTest.Scientist();

    Integer propertyValue = source.get("person_id", Integer.class);
    returnValue.setId(propertyValue);

    String propertyValue1 = source.get("person_name", String.class);
    returnValue.setName(propertyValue1);
    return returnValue;
  }

Also, the documentation does not specify whether to add getter and setter methods for computed values. So, they are removed from entity class

1 Answers1

0

When using @GetEntity methods, it is your responsibility to provide a result set object that is 100% compatible with the entity definition.

Here your Scientist entity contains two regular fields: person_id (integer) and person_name (text). Therefore your result set must contain (at least) two columns with these names and types.

But you said you provided the following query: select person_id,writetime(person_name) as name_ts from beam_ks.scientist where person_id=10.

This query does not contain the required columns. You should change your query to the one below, or something similar:

select person_id, person_name from beam_ks.scientist where person_id=10

Note that @GetEntity methods do not recognize computed values, only regular ones. It is not necessary to include writetime(person_name) as name_ts, it won't be mapped anyway.

adutra
  • 4,231
  • 1
  • 20
  • 18
  • BTW if you can't control the query and would like to retrieve the driver 3.x behavior of being resilient to incomplete result sets, I created https://datastax-oss.atlassian.net/browse/JAVA-2935. – adutra Apr 20 '21 at 09:47
  • Thanks @adutra, [https://datastax-oss.atlassian.net/browse/JAVA-2935](https://datastax-oss.atlassian.net/browse/JAVA-2935) this is the feature that we needed and the flexibility will help a lot to the community as well – Satwik Bhandiwad Apr 20 '21 at 10:04
  • Would you be able to provide a PR for it? We are looking for contributors. – adutra Apr 21 '21 at 14:25