首页 文章

尝试使用cassandra和spring-data-cassandra的复合主键时的异常

提问于
浏览
1

我正在玩spring-data和cassandra,看看如何编写一个服务,它必须在cassandra环中存储来自REST服务的数据,没有问题,但是当我尝试从cassandra中检索数据时,我想使用一个复合主键,我面临一个ClassCastException .

我已经在之前的post中看到了类似的问题,但解决方案对我不起作用 . 我已经看过another但这与spring-data-cassandra有关,没有spring-data-rest .

这是@Table anotated类:

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 +
            '}';
}

...

}

这是AdminUserPK:

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("some@company.com");
        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)

这个问题必须与带有@Query的AdminUserRepository接口相关,但是如何传递UUID和String,它将来自参数的主键复合到spring-data-cassandra需要的最终主键?

1 回答

  • 2

    现在它可以工作,我可以在Cassandra表中使用复合键 . 我必须将PrimaryKeyColumn字段放在同一个@Table anotated pojo而不是Primary Class中,并且复合键的类型必须是String或Long或者您认为的任何内容 . 我无法使用UUID课程,但我可以忍受它 .

    这是@Table anotated类:

    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);
    }
    

    该服务看起来与以前相同 .

    谢谢你,祝你有美好的一天!

相关问题