【问题标题】:How to query on subset of composite primary key?如何查询复合主键的子集?
【发布时间】:2017-10-14 05:16:36
【问题描述】:

我有以下课程:

@Entity
@Table(name = "my_entity")
@JsonIgnoreProperties(ignoreUnknown = true)
public class MyEntity {
    @EmbeddedId
    private Pk id;

    public Pk getId() {
        return id;
    }

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

}

@Embeddable
public class Pk implements Serializable {
    private static final long serialVersionUID = -3090221844117493661L;
    private Integer type;
    private String userId;

    public Pk() {
    }

    public Pk(String userId, Integer type) {
        this.setUserId(userId);
        this.setType(type);
    }

    public Integer getType() {
        return type;
    }

    public String getUserId() {
        return userId;
    }

    public void setType(Integer type) {
        this.type = type;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    // Auto-generated by Eclipse.
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((type == null) ? 0 : type.hashCode());
        result = prime * result + ((userId == null) ? 0 : userId.hashCode());
        return result;
    }

    // Auto-generated by Eclipse.
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Pk other = (Pk) obj;
        if (type != other.type)
            return false;
        if (userId == null) {
            if (other.userId != null)
                return false;
        } else if (!userId.equals(other.userId))
            return false;
        return true;
    }

}

public interface MyEntityRepository extends JpaRepository<MyEntity, Pk> {

    List<MyEntity> findAllByUserId(String userId);

}

当我初始化 Spring Data JPA 时出现错误:

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myEntityRepository': Invocation of init method failed; nested exception is org.springframework.data.mapping.PropertyReferenceException: No property user found for type MyEntity!
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1512)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:521)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:296)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:293)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:615)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
    at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:73)
    at com.myproject.backend.common.ServiceContext.start(ServiceContext.java:293)
    at com.myproject.run(AbstractServiceContainer.java:55)
    at com.myproject..run(AbstractServiceContainer.java:1)
    at io.dropwizard.cli.EnvironmentCommand.run(EnvironmentCommand.java:42)
    at io.dropwizard.cli.ConfiguredCommand.run(ConfiguredCommand.java:76)
    at io.dropwizard.cli.Cli.run(Cli.java:70)
    at io.dropwizard.Application.run(Application.java:72)
    at com.myproject..main(CombinedServiceContainer.java:106)
Caused by: org.springframework.data.mapping.PropertyReferenceException: No property user found for type MyEntity!
    at org.springframework.data.mapping.PropertyPath.<init>(PropertyPath.java:75)
    at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:327)
    at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:359)
    at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:307)
    at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:270)
    at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:241)
    at org.springframework.data.repository.query.parser.Part.<init>(Part.java:76)
    at org.springframework.data.repository.query.parser.PartTree$OrPart.<init>(PartTree.java:213)
    at org.springframework.data.repository.query.parser.PartTree$Predicate.buildTree(PartTree.java:321)
    at org.springframework.data.repository.query.parser.PartTree$Predicate.<init>(PartTree.java:301)
    at org.springframework.data.repository.query.parser.PartTree.<init>(PartTree.java:85)
    at org.springframework.data.jpa.repository.query.PartTreeJpaQuery.<init>(PartTreeJpaQuery.java:60)
    at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:91)
    at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateIfNotFoundQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:168)
    at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:69)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.<init>(RepositoryFactorySupport.java:320)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:169)
    at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.initAndReturn(RepositoryFactoryBeanSupport.java:224)
    at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:210)
    at org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.afterPropertiesSet(JpaRepositoryFactoryBean.java:92)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1571)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1509)
    ... 18 more

问题:Spring Data JPA 不支持查询主键的子集吗?或者我需要为此实现自定义存储库方法吗?

【问题讨论】:

    标签: hibernate spring-data-jpa


    【解决方案1】:

    您需要告诉 JPA 在哪里查找 userId 字段(即在嵌入的 id 中)。 如果您将存储库方法的名称更改为findAllByIdUserId,它应该可以工作。

    【讨论】:

    • 这应该是公认的答案。如果您发布您的答案here 我会接受。
    • @StefanDeitmer 查看我的版本这个问题:stackoverflow.com/q/46711695/2084253
    • 我正在处理一个由 3 个部分组成的复合主键; Spring JPA 很好地为我生成了一个实现(实体中的嵌入 ID 称为 key;注意它在方法名称中出现了两次):List&lt;Thing&gt; findAllByKeyFileDateAndKeyFormNumber(LocalDate fileDate, int formNumber);
    【解决方案2】:

    好的,我也尝试使用 @IdClass 来代替:

    @Entity
    @Table(name = "my_entity")
    @JsonIgnoreProperties(ignoreUnknown = true)
    @IdClass(Pk.class)
    public class MyEntity {
        @Id private Integer type;
        @Id private String userId;
    
        public Pk getId() {
            return id;
        }
    
        public void setId(Pk id) {
            this.id = id;
        }
    
    }
    
    @IdClass(Pk.class)
    public class Pk implements Serializable {
        private static final long serialVersionUID = -3090221844117493661L;
        private Integer type;
        private String userId;
    
        public Pk() {
        }
    
        public Pk(String userId, Integer type) {
            this.setUserId(userId);
            this.setType(type);
        }
    
        public Integer getType() {
            return type;
        }
    
        public String getUserId() {
            return userId;
        }
    
        public void setType(Integer type) {
            this.type = type;
        }
    
        public void setUserId(String userId) {
            this.userId = userId;
        }
    
        // Auto-generated by Eclipse.
        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((type == null) ? 0 : type.hashCode());
            result = prime * result + ((userId == null) ? 0 : userId.hashCode());
            return result;
        }
    
        // Auto-generated by Eclipse.
        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            Pk other = (Pk) obj;
            if (type != other.type)
                return false;
            if (userId == null) {
                if (other.userId != null)
                    return false;
            } else if (!userId.equals(other.userId))
                return false;
            return true;
        }
    
    }
    

    这确实给了我一条不同的错误消息,NullPointerException,这暗示我 Spring Data JPA 无法为 findAllByUserId(...) 构建查询。我对那个查询方法做了一个自定义实现:

    public interface MyEntityRepository extends JpaRepository<MyEntity, Pk>, MyEntityRepositoryCustom {
    
    }
    
    public interface MyEntityRepositoryCustom {
    
        List<MyEntity> findAllByUserId(String userId);
    
    }
    
    public class MyEntityRepositoryImpl implements MyEntityRepositoryCustom {
    
        @PersistenceContext
        private EntityManager em;
    
        @Override
        public List<MyEntityRepositoryCustom> findAllByUserId(String userId) {
            return em
                    .createQuery("select o from MyEntity o where o.userId=:userId",
                            MyEntity.class).setParameter("userId", userId).getResultList();
        }
    
    }
    

    ...瞧,它有效!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-16
      • 2014-06-22
      • 1970-01-01
      • 2018-08-01
      • 2011-06-05
      • 1970-01-01
      相关资源
      最近更新 更多