springdatacassandra は、POJO で Cassandra によって提供されるユーザー定義のデータ型をどのようにサポートしますか? UDT の注釈を探しています。
2 に答える
Spring data cassandra の最新バージョン (1.2.0.BUILD-SNAPSHOT) は、datastax ドライバー 2.0.4 に依存します。datastax ドライバー 2.1.x 以降では、UDT がサポートされています。
datastax ドライバーを 2.1.x にオーバーライドして、2.1 ドライバーが提供する最新の機能を利用することができます。
<dependency>
<groupId>com.datastax.cassandra</groupId>
<artifactId>cassandra-driver-mapping</artifactId>
<version>2.1.9</version>
</dependency>
が必要ですが、全体としては機能しません。Spring Data cassandra は UDT マッピングをサポートしていません。
詳細はこちら: https://jira.spring.io/browse/DATACASS-172
私はこの問題に直面し、デバッグプロセスは、Spring Data cassandra が @Table、@Persistent、または @PrimaryKeyClass アノテーションのみをチェックし、別のケースで例外を発生させることを示しました
> init メソッドの呼び出しに失敗しました。ネストされた例外は org.springframework.data.cassandra.mapping.VerifierMappingExceptions です: Cassandra エンティティには @Table、@Persistent、または @PrimaryKeyClass アノテーションが必要です
しかし、私は解決策を見つけました。UDT を含むエンティティと含まないエンティティを管理できるアプローチを見つけました。私のアプリケーションでは、Spring cassandra データ プロジェクトを使用して、直接 datastax コア ドライバーを使用しています。UDT を含むオブジェクトを含まないリポジトリは、Spring cassanta データ アプローチを使用し、UDT を含むオブジェクトはカスタム リポジトリを使用します。カスタム リポジトリは datastax マッパーを使用し、UDT で正しく動作します (これらは別のパッケージにあります。必要な理由については以下の注を参照してください)。
package com.fyb.cassandra.custom.repositories.impl;
import java.util.List;
import java.util.UUID;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.cassandra.config.CassandraSessionFactoryBean;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.mapping.Mapper;
import com.datastax.driver.mapping.MappingManager;
import com.datastax.driver.mapping.Result;
import com.google.common.collect.Lists;
import com.fyb.cassandra.custom.repositories.AccountDeviceRepository;
import com.fyb.cassandra.dto.AccountDevice;
public class AccountDeviceRepositoryImpl implements AccountDeviceRepository {
@Autowired
public CassandraSessionFactoryBean session;
private Mapper<AccountDevice> mapper;
@PostConstruct
void initialize() {
mapper = new MappingManager(session.getObject()).mapper(AccountDevice.class);
}
@Override
public List<AccountDevice> findAll() {
return fetchByQuery("SELECT * FROM account_devices");
}
@Override
public void save(AccountDevice accountDevice) {
mapper.save(accountDevice);
}
@Override
public void deleteByConditions(UUID accountId, UUID systemId, UUID deviceId) {
final String query = "DELETE FROM account_devices where account_id =" + accountId + " AND system_id=" + systemId
+ " AND device_id=" + deviceId;
session.getObject().execute(query);
}
@Override
public List<AccountDevice> findByAccountId(UUID accountId) {
final String query = "SELECT * FROM account_devices where account_id=" + accountId;
return fetchByQuery(query);
}
/*
* Take any valid CQL query and try to map result set to the given list of appropriates <T> types.
*/
private List<AccountDevice> fetchByQuery(String query) {
ResultSet results = session.getObject().execute(query);
Result<AccountDevice> accountsDevices = mapper.map(results);
List<AccountDevice> result = Lists.newArrayList();
for (AccountDevice accountsDevice : accountsDevices) {
result.add(accountsDevice);
}
return result;
}
}
また、UDT オブジェクトを含まないエンティティの管理を担当する Spring データ関連のリポジトリは次のようになります。
package com.fyb.cassandra.repositories;
import org.springframework.data.cassandra.repository.CassandraRepository;
import com.fyb.cassandra.dto.AccountUser;
import org.springframework.data.cassandra.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.UUID;
@Repository
public interface AccountUserRepository extends CassandraRepository<AccountUser> {
@Query("SELECT * FROM account_users WHERE account_id=?0")
List<AccountUser> findByAccountId(UUID accountId);
}
このソリューションをテストしましたが、100% 動作します。さらに、POJO オブジェクトを添付しました。
データスタックス注釈のみを使用する Pojo:
package com.fyb.cassandra.dto;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import com.datastax.driver.mapping.annotations.ClusteringColumn;
import com.datastax.driver.mapping.annotations.Column;
import com.datastax.driver.mapping.annotations.Frozen;
import com.datastax.driver.mapping.annotations.FrozenValue;
import com.datastax.driver.mapping.annotations.PartitionKey;
import com.datastax.driver.mapping.annotations.Table;
@Table(name = "account_systems")
public class AccountSystem {
@PartitionKey
@Column(name = "account_id")
private java.util.UUID accountId;
@ClusteringColumn
@Column(name = "system_id")
private java.util.UUID systemId;
@Frozen
private Location location;
@FrozenValue
@Column(name = "user_token")
private List<UserToken> userToken;
@Column(name = "product_type_id")
private int productTypeId;
@Column(name = "serial_number")
private String serialNumber;
}
UDT を使用せず、春のデータ cassandra フレームワークのみを使用する Pojo:
package com.fyb.cassandra.dto;
import java.util.Date;
import java.util.UUID;
import org.springframework.cassandra.core.PrimaryKeyType;
import org.springframework.data.cassandra.mapping.Column;
import org.springframework.data.cassandra.mapping.PrimaryKeyColumn;
import org.springframework.data.cassandra.mapping.Table;
@Table(value = "accounts")
public class Account {
@PrimaryKeyColumn(name = "account_id", ordinal = 0, type = PrimaryKeyType.PARTITIONED)
private java.util.UUID accountId;
@Column(value = "account_name")
private String accountName;
@Column(value = "currency")
private String currency;
}
以下のエンティティは異なる注釈を使用していることに注意してください。
@PrimaryKeyColumn(name = "account_id", ordinal = 0, type = PrimaryKeyType.PARTITIONED)and @PartitionKey
@ClusteringColumn and @PrimaryKeyColumn(name = "area_parent_id", ordinal = 2, type = PrimaryKeyType.CLUSTERED)
一見すると不便ですが、UDT を含むオブジェクトと含まないオブジェクトを操作できます。
重要な注意事項が 1 つあります。その 2 つのリポジトリ (UDT を使用し、別のパッケージに存在してはならない) により、Spring 構成はリポジトリを持つ基本パッケージを探します。
@Configuration
@EnableCassandraRepositories(basePackages = {
"com.fyb.cassandra.repositories" })
public class CassandraConfig {
..........
}