我正在使用 spring-data 和 cassandra,了解如何编写一个必须在 cassandra 环中存储来自 REST 服务的数据的服务,这没有问题,但是当我尝试从 cassandra 检索数据时,我想使用复合主键,我面临 ClassCastException。
我已经在之前的post中看到了类似的问题,但该解决方案对我不起作用。我已经看到了 another 但这与 spring-data-cassandra 有关,没有 spring-data-rest。
这是@Table注解的类:
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.cassandra.mapping.PrimaryKey;
import org.springframework.data.cassandra.mapping.Table;
import java.time.LocalDateTime;
import java.util.Map;
import javax.validation.constraints.NotNull;
@Table(value=AdminUserCassandraTable.tableName)
public class AdminUserCassandraTable {
@org.springframework.data.annotation.Transient
public static final String tableName = "AdminUser";
@PrimaryKey
private AdminUserPK id;
private String tenantId;
private String orgId;
private boolean superAdmin;
@NotNull
private String password;
private String emailAddress;
private Map<String, String> metadata;
@CreatedDate
private LocalDateTime createdAt;
@LastModifiedDate
private LocalDateTime lastModified;
public AdminUserCassandraTable() {
this.id = null;
}
@Override public String toString() {
return "AdminUserCassandraTable{" +
"id=" + id +
", tenantId='" + tenantId + '\'' +
", orgId='" + orgId + '\'' +
", superAdmin=" + superAdmin +
", password='" + password + '\'' +
", emailAddress='" + emailAddress + '\'' +
", metadata=" + metadata +
", createdAt=" + createdAt +
", lastModified=" + lastModified +
'}';
}
...
}
这是管理员用户PK:
import java.io.Serializable;
import java.util.UUID;
import org.springframework.cassandra.core.PrimaryKeyType;
import org.springframework.data.cassandra.mapping.CassandraType;
import org.springframework.data.cassandra.mapping.PrimaryKeyClass;
import org.springframework.data.cassandra.mapping.PrimaryKeyColumn;
import com.datastax.driver.core.DataType;
@PrimaryKeyClass
public class AdminUserPK implements Serializable{
@PrimaryKeyColumn(name = "id", ordinal = 0, type = PrimaryKeyType.PARTITIONED)
@CassandraType(type = DataType.Name.UUID)
private UUID id;
@PrimaryKeyColumn(name = "username", ordinal = 1, type = PrimaryKeyType.PARTITIONED)
@CassandraType(type = DataType.Name.TEXT)
private String username;
// https://stackoverflow.com/questions/34363344/querying-tables-with-composite-primary-keys-using-spring-data-cassandra
public AdminUserPK() {
this.id = null;
this.username = null;
}
public AdminUserPK(UUID id, String username) {
this.id = id;
this.username = username;
}
...
getters, setters, equals and hashCode methods.
}
这是AdminUserRepository:
import java.util.Optional;
import java.util.UUID;
import org.springframework.data.cassandra.repository.CassandraRepository;
import org.springframework.data.cassandra.repository.Query;
import org.springframework.data.cassandra.repository.TypedIdCassandraRepository;
import unicon.matthews.admin.AdminUser;
import unicon.matthews.admin.service.AdminUserCassandraTable;
import unicon.matthews.admin.service.AdminUserPK;
public interface AdminUserRepository extends TypedIdCassandraRepository<AdminUserCassandraTable, AdminUserPK> {
**The problem must be here, with this @Query.**
@Query("select * from AdminUser where id = ?0 and username = ?1")
Optional<AdminUser> findByIdAndUsername(final UUID id,final String userName);
}
最后是引发异常的测试用例:
import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.util.Version;
import org.springframework.test.context.junit4.SpringRunner;
import example.springdata.cassandra.util.CassandraKeyspace;
import unicon.matthews.admin.AdminUser;
import unicon.matthews.admin.service.AdminUserCassandraTable;
import unicon.matthews.admin.service.AdminUserPK;
import unicon.matthews.admin.service.repository.AdminUserRepository;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = unicon.matthews.admin.service.repository.CassandraConfiguration.class)
public class AdminUserRepositoryTests {
final String userName = UUID.randomUUID().toString();
final UUID _id = UUID.randomUUID();
@ClassRule public final static CassandraKeyspace CASSANDRA_KEYSPACE = CassandraKeyspace.onLocalhost().atLeast(Version.parse("3.0"));
@Autowired AdminUserRepository repository;
@Before
public void setUp() throws Exception {
repository.deleteAll();
AdminUserCassandraTable aPojo = new AdminUserCassandraTable();
AdminUserPK adminUserPK = new AdminUserPK();
adminUserPK.setId(_id);
adminUserPK.setUsername(userName);
aPojo.setId(adminUserPK);
aPojo.setEmailAddress("[email protected]");
aPojo.setOrgId("orgId");
aPojo.setPassword("pass");
aPojo.setTenantId("tenantId");
aPojo.setCreatedAt(LocalDateTime.now());
aPojo.setLastModified(null);
// OJITO! metadatos a null...
aPojo.setMetadata(null);
aPojo.setSuperAdmin(Boolean.FALSE);
repository.save(aPojo);
assertTrue(repository.count() > 0);
}
@Test
public void testFindByIdAndUsername() {
Optional<AdminUser> loadedUserName = repository.findByIdAndUsername(_id,userName);
assertNotNull(loadedUserName);
assertEquals("something went wrong!",userName,loadedUserName.get().getUsername());
}
}
例外情况是:
java.lang.ClassCastException: Cannot cast unicon.matthews.admin.service.AdminUserPK to java.lang.String
at java.lang.invoke.MethodHandleImpl.newClassCastException(MethodHandleImpl.java:361)
at java.lang.invoke.MethodHandleImpl.castReference(MethodHandleImpl.java:356)
at unicon.matthews.admin.AdminUser_Accessor_cmi9qy.setProperty(Unknown Source)
at org.springframework.data.cassandra.repository.query.DtoInstantiatingConverter$2.doWithPersistentProperty(DtoInstantiatingConverter.java:101)
at org.springframework.data.mapping.model.BasicPersistentEntity.doWithProperties(BasicPersistentEntity.java:346)
at org.springframework.data.cassandra.repository.query.DtoInstantiatingConverter.convert(DtoInstantiatingConverter.java:92)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:221)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter$1.convert(ResultProcessor.java:209)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:221)
at org.springframework.data.repository.query.ResultProcessor.processResult(ResultProcessor.java:162)
at org.springframework.data.cassandra.repository.query.CassandraQueryExecution$ResultProcessingConverter.convert(CassandraQueryExecution.java:178)
at org.springframework.data.cassandra.repository.query.CassandraQueryExecution$ResultProcessingExecution.execute(CassandraQueryExecution.java:143)
at org.springframework.data.cassandra.repository.query.AbstractCassandraQuery.execute(AbstractCassandraQuery.java:113)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:483)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:461)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:56)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy96.findByIdAndUsername(Unknown Source)
at unicon.mattheews.admin.service.repository.test.AdminUserRepositoryTests.testFindByIdAndUsername(AdminUserRepositoryTests.java:120)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:48)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
问题一定与AdminUserRepository接口有关,带有@Query,但是我如何将UUID和组合来自参数的主键的字符串传递给spring-data-cassandra需要的最终主键?
现在可以了,我可以在 Cassandra 表中使用复合键。 我必须将 PrimaryKeyColumn 字段放在同一个 @Table 注释的 pojo 中,而不是 Primary Class 中,并且复合键的类型必须是 String 或 Long 或您认为的任何类型。我无法让它与 UUID 类一起工作,但我可以忍受它。
这是@Table注解的类:
import org.springframework.cassandra.core.Ordering;
import org.springframework.cassandra.core.PrimaryKeyType;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.cassandra.mapping.CassandraType;
import org.springframework.data.cassandra.mapping.Column;
import org.springframework.data.cassandra.mapping.PrimaryKeyColumn;
import org.springframework.data.cassandra.mapping.Table;
import java.time.LocalDateTime;
import java.util.Map;
import javax.validation.constraints.NotNull;
import com.datastax.driver.core.DataType;
@Table(value=AdminUserCassandraTable.tableName)
public class AdminUserCassandraTable {
@org.springframework.data.annotation.Transient
public static final String tableName = "AdminUser";
@PrimaryKeyColumn(name = "id", ordinal = 0, type = PrimaryKeyType.PARTITIONED)
@CassandraType(type = DataType.Name.TEXT)
private String id;
@PrimaryKeyColumn(name = "username", ordinal = 1, type = PrimaryKeyType.CLUSTERED,ordering = Ordering.ASCENDING)
@CassandraType(type = DataType.Name.TEXT)
private String username;
@Column("tenant_id")
private String tenantId;
@Column("org_id")
private String orgId;
@Column("is_superAdmin")
private boolean superAdmin;
@NotNull
@Column("password")
private String password;
@Column("email_address")
private String emailAddress;
@Column("metadata")
private Map<String, String> metadata;
@CreatedDate
@Column("created_at")
private LocalDateTime createdAt;
@LastModifiedDate
@Column("last_modified")
private LocalDateTime lastModified;
public static String getTableName() {
return tableName;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getTenantId() {
return tenantId;
}
public void setTenantId(String tenantId) {
this.tenantId = tenantId;
}
public String getOrgId() {
return orgId;
}
public void setOrgId(String orgId) {
this.orgId = orgId;
}
public boolean isSuperAdmin() {
return superAdmin;
}
public void setSuperAdmin(boolean superAdmin) {
this.superAdmin = superAdmin;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
public Map<String, String> getMetadata() {
return metadata;
}
public void setMetadata(Map<String, String> metadata) {
this.metadata = metadata;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
public LocalDateTime getLastModified() {
return lastModified;
}
public void setLastModified(LocalDateTime lastModified) {
this.lastModified = lastModified;
}
}
CassandraRepository 看起来像:
import java.util.Optional;
import org.springframework.data.cassandra.repository.CassandraRepository;
import org.springframework.data.cassandra.repository.Query;
import unicon.matthews.admin.AdminUser;
import unicon.matthews.admin.service.AdminUserCassandraTable;
public interface AdminUserRepository extends CassandraRepository<AdminUserCassandraTable> {
@Query("select * from AdminUser where username = ?0 ALLOW FILTERING")
Optional<AdminUser> findByUsername(final String userName);
@Query("select * from AdminUser where id = ?0 ALLOW FILTERING")
Optional<AdminUser> findById(final String id);
@Query("select * from AdminUser where id = ?0 and username = ?1")
Optional<AdminUser> findByIdAndUsername(final String id,final String userName);
}
服务看起来和以前一样。
谢谢您,祝您有愉快的一天!
我创建了一个开源 Cassandra JHipster 8.6.0 复合主键蓝图。如果您感兴趣,可以在这里找到蓝图和示例的代码:https://github.com/amarpatel-xx/jhipster-cassandra-composite-primary-key-example