It is just an exercise to understand how to use CriteriaBuilder and EntityManager with join. I want to join class Product with Customer and select each product that have the requested customer_id.
I have a class Product and Customer as follow:
@Entity
public class Product {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String name;
@ManyToOne(optional = false)
@JoinColumn(name = "customer_id", nullable = false)
@OnDelete(action = OnDeleteAction.CASCADE)
private Customer customer;
...
}
And Customer:
@Entity
public class Customer {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String firstName;
private String lastName;
...
}
Basically I want what I could easiily achieve with this interface:
public interface ProductRepository extends JpaRepository<Product, String>{
List<Product> findByCustomerId(Long custsomerId);
}
I tried as follow with no luck:
public class ProductRepositoryCustomImpl implements ProductRepositoryCustom {
@PersistenceContext
private EntityManager em;
@Override
public List<Product> join(Long customerId) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Product> cq = cb.createQuery(Product.class);
Root<Product> from = cq.from(Product.class);
Metamodel m = em.getMetamodel();
EntityType<Customer> CustomerMeta = m.entity(Customer.class);
Join<Product, Customer> join = from.join(CustomerMeta.getId(Customer.class));
ParameterExpression<Long> p = cb.parameter(Long.class);
CriteriaQuery<Product> query = cq.multiselect(join).where(cb.equal(join.get("customer_id"), p));
TypedQuery<Product> typedQuery = em.createQuery(query);
typedQuery.setParameter(p, customerId);
List<Product> results = typedQuery.getResultList();
return results;
}
}
I get this error:
java.lang.IllegalStateException: Failed to execute CommandLineRunner
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:821) [spring-boot-2.0.5.RELEASE.jar:2.0.5.RELEASE]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:802) [spring-boot-2.0.5.RELEASE.jar:2.0.5.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:341) [spring-boot-2.0.5.RELEASE.jar:2.0.5.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1277) [spring-boot-2.0.5.RELEASE.jar:2.0.5.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1265) [spring-boot-2.0.5.RELEASE.jar:2.0.5.RELEASE]
at com.jpa.jpaExample.JpaExampleApplication.main(JpaExampleApplication.java:19) [classes/:na]
Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: Attribute [com.jpa.jpaExample.Customer#id : java.lang.Long] not castable to requested type [com.jpa.jpaExample.Customer]; nested exception is java.lang.IllegalArgumentException: Attribute [com.jpa.jpaExample.Customer#id : java.lang.Long] not castable to requested type [com.jpa.jpaExample.Customer]
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:367) ~[spring-orm-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:225) ~[spring-orm-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:527) ~[spring-orm-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61) ~[spring-tx-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242) ~[spring-tx-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153) ~[spring-tx-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:135) ~[spring-data-jpa-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) ~[spring-data-commons-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at com.sun.proxy.$Proxy75.join(Unknown Source) ~[na:na]
try this:
Join<Product, Customer> join = from.join(from.get("customer"));
instead of:
Join<Product, Customer> join = from.join(CustomerMeta.getId(Customer.class));
from refers to the Product class, so when creating the extended relationship it will be based on a parameter of this class.
It can be accessed like this or from the metamodel (for my taste, the recommended one)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.