Spring Data Cassandra: как запрашивать таблицы с составными ключами?

У меня есть следующее семейство столбцов:

@Table(value = "request_event")
public class RequestEvent {

    @PrimaryKeyColumn(name = "day_requested", ordinal = 0, type = PrimaryKeyType.PARTITIONED)
    private LocalDate dayRequested;

    @PrimaryKeyColumn(name = "date_requested", ordinal = 1, type = PrimaryKeyType.CLUSTERED, ordering = Ordering.DESCENDING)
    private LocalDateTime dateRequested;

    ...
}

который хранится и доступен в хранилище:

@Repository
public interface RequestEventRepository extends CrudRepository<RequestEvent, LocalDateTime> {
}

к несчастью requestEventRepository.findOne(localDate) генерирует исключение, вероятно, потому что возвращает несколько результатов. Как я могу это исправить? Кроме того, как можно получить все результаты за определенный день?

2 ответа

Решение

У вас есть два варианта представления составных ключей в Spring Data Cassandra:

  1. С помощью @PrimaryKeyColumn в типе домена (как вы сделали).
  2. Используя @PrimaryKeyClass представлять первичный ключ и встраивать его в тип домена.

Репозитории Spring Data допускают использование одного ID тип. Поэтому невозможно просто объявить LocalDateTime как идентификатор Если вы хотите придерживаться @PrimaryKeyColumn внутри типа домена, использование MapId как тип идентификатора:

@Table(value = "request_event")
public class RequestEvent {

    @PrimaryKeyColumn(name = "day_requested", ordinal = 0,
            type = PrimaryKeyType.PARTITIONED) 
    private LocalDate dayRequested;

    @PrimaryKeyColumn(name = "date_requested", ordinal = 1, type = PrimaryKeyType.CLUSTERED,
            ordering = Ordering.DESCENDING) 
    private LocalDateTime dateRequested;

}

public interface RequestEventRepository extends CrudRepository<RequestEvent, MapId> {}

MapId mapId = BasicMapId.id("dayRequested", …).with("dateRequested", …);

RequestEvent loaded = eventRepository.findOne(mapId);

Если вы решили представить свой первичный ключ как объект значения, то вам нужно немного изменить тип своего домена:

@PrimaryKeyClass
public class Key implements Serializable {

    @PrimaryKeyColumn(name = "day_requested", ordinal = 0,
            type = PrimaryKeyType.PARTITIONED) 
    private LocalDate dayRequested;

    @PrimaryKeyColumn(name = "date_requested", ordinal = 1, type = PrimaryKeyType.CLUSTERED,
            ordering = Ordering.DESCENDING) 
    private LocalDateTime dateRequested;

}

@Table(value = "request_event")
public class RequestEvent {

    @PrimaryKey 
    private Key key;

}

public interface RequestEventRepository extends CrudRepository<RequestEvent, Key> {}

eventRepository.findOne(new Key(…))

Я просто хотел бы добавить, что последние версии spring-data-cassandra включают новый интерфейс репозитория, который устраняет необходимость указывать Primary Keys или же MapId в главном интерфейсе репозитория.

Использовать MapIdCassandraRepository вместо CassandraRepository:

public interface MyTableRepository extends MapIdCassandraRepository<MyTable> {
}

Как вы можете видеть в приведенном выше коде, расширение MapIdCassandraRepository интерфейс требует только указать желаемую таблицу.

Ссылка:https://docs.spring.io/spring-data/cassandra/docs/current/reference/html/#cassandra.migration

Просто создайте дополнительные методы запроса в RequestEventRepository.

@Repository
public interface RequestEventRepository extends CrudRepository<RequestEvent, LocalDateTime> {
    List<RequestEvent> findAllByDayRequested(LocalDateTime day);
    RequestEvent findOneByDayRequestedAndDateRequested(LocalDateTime day, LocalDateTime localDateTime);
}

Если вы хотите выполнить поиск по ключу раздела вашего ключевого класса, вам необходимо добавить новый метод в интерфейс репозитория. Новое имя метода будет соответствовать этому соглашению.

//{MethodName}{PrimaryKeyClassName}{PrimaryKeyColumn}

ПРИМЕР:

@PrimaryKeyClass
public class UserKey implements Serializable {
    private static final long serialVersionUID = 1L;
    @PrimaryKeyColumn(name = "email", type = PrimaryKeyType.PARTITIONED)
    private String email;
    @PrimaryKeyColumn(name = "firstname", ordinal = 0, type = PrimaryKeyType.CLUSTERED, ordering = Ordering.DESCENDING)
    private String firstName;
    @PrimaryKeyColumn(name = "lastname", ordinal = 1, type = PrimaryKeyType.CLUSTERED, ordering = Ordering.ASCENDING)
    private String lastName;
    //equals and hashcode methods
}

Тогда имя метода будет

User findByUserKeyEmail(String email);
Другие вопросы по тегам