How is it possible to access pre-filtered dependent entities from Associations retrieved via JPA/Hibernate criteria query with restrictions? - jpa

I have a provider:user=1:N association modeled with entities, Hibernate/JPA.
Then I want to query a provider/user pair via restrictions on attributes of the dependent entity, like certain values for the attributes of the user, let’s say its id, date of birth, etc.
The logged sql has a proper join and all the attributes of the two entities in the select. I tried it manually, it returns the expected single row.
Thus, on entity level, I expect a single provider entity to be returned with the user list containing the queried user.
Indeed, the corresponding provider entity is returned, but when I then want to access the user via the provider’s user list, it hits the DB a second time and reads all users of the provider totally neglecting my restrictions of the query.
The observed behavior is the same for queries formulated with HQL, Hibernate Criteria (also with #Filter), JPA CriteriaBuilder.
What am I missing here?
Do those restrictions only affect the selection of the root entities (which is provider in my case)?
The problem is sketched on
https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/querycriteria.html
Under 5.4 Associations it says:
The kittens collections held by the Cat instances returned by the previous two queries are not pre-filtered by the criteria. If you want to retrieve just the kittens that match the criteria, you must use a ResultTransformer.
Is this thus the intended behavior for this kind of API?
Or is there a convenient possibility to access just the restricted sub set of the dependent entities?
Regards,
Wolfgang

Here comes some source code to precise my verbal description above.
Provider and User table.
drop table EX_USER;
drop table EX_PROVIDER;
create table EX_PROVIDER
( id number(*,0) not null
,name varchar2(255) not null
,primary key (id)
);
insert into EX_PROVIDER (id,name) values (0 ,'Provider_A');
insert into EX_PROVIDER (id,name) values (1 ,'Provider_B');
commit;
create table EX_USER
( id number(*,0) not null
, ex_provider_id number(*,0) not null
,name varchar2(255)
,location varchar2(255)
,primary key (id)
,constraint ex_user_provider_fk foreign key(ex_provider_id) references EX_PROVIDER(id)
);
insert into EX_USER (id,ex_provider_id,name,location) values (0,0,'User_1','Munich');
insert into EX_USER (id,ex_provider_id,name,location) values (1,0,'User_2','Berlin');
insert into EX_USER (id,ex_provider_id,name,location) values (2,1,'User_3','Munich');
commit;
Entities generated with Eclipse "JPA Tools".
#Entity
#Table(name="EX_PROVIDER")
#NamedQuery(name="ExProvider.findAll", query="SELECT e FROM ExProvider e")
public class ExProvider implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#SequenceGenerator(name="EX_PROVIDER_ID_GENERATOR", sequenceName="KONST_SD_SEQ")
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="EX_PROVIDER_ID_GENERATOR")
private long id;
private String name;
//bi-directional many-to-one association to ExUser
#OneToMany(mappedBy="exProvider",fetch=FetchType.LAZY)
private Set<ExUser> exUsers=new HashSet<ExUser>();
public ExProvider() {
}
public long getId() {
return this.id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Set<ExUser> getExUsers() {
return this.exUsers;
}
public void setExUsers(Set<ExUser> exUsers) {
this.exUsers = exUsers;
}
public ExUser addExUser(ExUser exUser) {
getExUsers().add(exUser);
exUser.setExProvider(this);
return exUser;
}
public ExUser removeExUser(ExUser exUser) {
getExUsers().remove(exUser);
exUser.setExProvider(null);
return exUser;
}
}
#Entity
#Table(name="EX_USER")
#NamedQuery(name="ExUser.findAll", query="SELECT e FROM ExUser e")
public class ExUser implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#SequenceGenerator(name="EX_USER_ID_GENERATOR", sequenceName="KONST_SD_SEQ")
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="EX_USER_ID_GENERATOR")
private long id;
private String location;
private String name;
//bi-directional many-to-one association to ExProvider
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="EX_PROVIDER_ID")
private ExProvider exProvider;
public ExUser() {
}
public long getId() {
return this.id;
}
public void setId(long id) {
this.id = id;
}
public String getLocation() {
return this.location;
}
public void setLocation(String location) {
this.location = location;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public ExProvider getExProvider() {
return this.exProvider;
}
public void setExProvider(ExProvider exProvider) {
this.exProvider = exProvider;
}
}
My intention with the below code was to retrieve Provider 0 (Provider_A) containing User 1 (Berlin) in its user list.
#SuppressWarnings("unchecked")
private void demo() {
EntityManager em = null;
try {
em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
try {
tx.begin();
Session session = (Session) em.getDelegate();
Criteria crit = session.createCriteria(ExProvider.class, "provider")
.createCriteria("exUsers", "user")
.add(Restrictions.eq("user.location","Berlin"))
;
List<ExProvider> providerList=(List<ExProvider>)crit.list();
logExProviderList(providerList);
tx.commit();
} finally {
if (tx!=null && tx.isActive()) tx.rollback();
}
} finally {
if (em!=null) em.close();
}
}
private void logExProviderList(List<ExProvider> providerList) {
for (ExProvider provider: providerList) {
logger.info("Criteria: provider=["+provider.getId()+"]");
for (ExUser user : provider.getExUsers()) {
logger.info("Criteria: user=["+user.getId()+"] name=["+user.getName()+"] location=["+user.getLocation()+"]");
}
}
}
The 1st SQL is what I expected. It is executed when crit.list() is called. On SQL level it returns the expected single row for Provider 0, User 1.
SELECT this_.id AS id43_1_,
this_.name AS name43_1_,
user1_.id AS id44_0_,
user1_.EX_PROVIDER_ID AS EX4_44_0_,
user1_.location AS location44_0_,
user1_.name AS name44_0_
FROM EX_PROVIDER this_
INNER JOIN EX_USER user1_
ON this_.id=user1_.EX_PROVIDER_ID
WHERE user1_.location=?;
However, this is not mapped to entity level as I expected. There, the restriction seems to affect the selection of the Provider only. When the user list is accessed, all users of the provider are read from DB neglecting the 'Berlin' restriction.
This was the same whether I used HQL, Hibernate Criteria (also with #Filter), JPA CriteriaBuilder.
SELECT exusers0_.EX_PROVIDER_ID AS EX4_43_1_,
exusers0_.id AS id1_,
exusers0_.id AS id44_0_,
exusers0_.EX_PROVIDER_ID AS EX4_44_0_,
exusers0_.location AS location44_0_,
exusers0_.name AS name44_0_
FROM EX_USER exusers0_
WHERE exusers0_.EX_PROVIDER_ID=?;
The log.
Criteria: provider=[0]
Criteria: user=[1] name=[User_2] location=[Berlin]
Criteria: user=[0] name=[User_1] location=[Munich]
I may achieve the expected result set using setResultTransformer(), but in this case the properly selected result is returned as some rows of entities.
#SuppressWarnings("unchecked")
private void demo() {
EntityManager em = null;
try {
em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
try {
tx.begin();
Session session = (Session) em.getDelegate();
Criteria crit = session.createCriteria(ExProvider.class, "provider")
.createCriteria("exUsers", "user")
.add(Restrictions.eq("user.location","Berlin"))
.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
;
List<ExProvider> providerList=(List<ExProvider>)crit.list();
logExProviderMapList(providerList);
tx.commit();
} finally {
if (tx!=null && tx.isActive()) tx.rollback();
}
} finally {
if (em!=null) em.close();
}
}
private void logExProviderMapList(List providerList) {
Iterator iter = providerList.iterator();
while ( iter.hasNext() ) {
Map map = (Map) iter.next();
ExProvider provider = (ExProvider) map.get("provider");
if(provider!=null) {
logger.info("Criteria: provider=["+provider.getId()+"]");
}
ExUser user = (ExUser) map.get("user");
if(user!=null) {
logger.info("Criteria: user=["+user.getId()+"] name=["+user.getName()+"] location=["+user.getLocation()+"]");
}
}
}
The SQL is the same as the 1st SQL above.
SELECT this_.id AS id43_1_,
this_.name AS name43_1_,
user1_.id AS id44_0_,
user1_.EX_PROVIDER_ID AS EX4_44_0_,
user1_.location AS location44_0_,
user1_.name AS name44_0_
FROM EX_PROVIDER this_
INNER JOIN EX_USER user1_
ON this_.id=user1_.EX_PROVIDER_ID
WHERE user1_.location=?;
The log.
Criteria: provider=[0]
Criteria: user=[1] name=[User_2] location=[Berlin]
My question was and is, whether it is possible to get this result as proper entity tree with Provider_A containing exactly the User from Berlin in its list.
Thanks again,
Wolfgang B

Related

JPA first level cache not clreared after completion of transaction

I am using JPA 2.1(with EclipseLink implementation), to get a record from Database.
By default it first level cache is enabled, it caches the record in PersistenceContext. If I try to get same record I will get it from first level cache, so no query will be fired on database second time.
Once transaction is over the first level cache will be cleared, and If I try to get same entry one more time, query has to be fired as the cache is cleared and it should come from database but it is not.
At least the query should be fired on database if I close the current entity manager,re-open it, and try to get the record.
Even now second query is not going to database. Once I get the record from the database first time(at this time I can see the select query in console logs), after wards if I try to get one more time, its coming from cache memory(as I can not see the query one more time in console logs, I am pretending that it is coming from cache), no matter what I do(use new transaction or close and re-open entity manager) the first level cache ain't cleared.
The code which I am using is below:
EntityManagerFactory entityManagerFactory=
Persistence.createEntityManagerFactory("01EmployeeBasics");
EntityManager entityManager=entityManagerFactory.createEntityManager();
System.out.println("EM1 : "+entityManager);
entityManager.getTransaction().begin();
System.out.println("Tx1 : "+entityManager.getTransaction());
Employee employee=entityManager.find(Employee.class, 123);
entityManager.getTransaction().commit();
entityManager.close();
entityManager=entityManagerFactory.createEntityManager();
System.out.println("EM2 : "+entityManager);
entityManager.getTransaction().begin();
System.out.println("Tx2 : "+entityManager.getTransaction());
Employee employee2=entityManager.find(Employee.class, 123);
entityManager.getTransaction().commit();
entityManager.close();
entityManagerFactory.close();
Employee class is as below:
package in.co.way2learn;
import javax.persistence.Entity;
import javax.persistence.Id;
#Entity
public class Employee {
#Id
private int id;
private String name;
private int salary;
public Employee() {
// TODO Auto-generated constructor stub
}
public Employee(int id, String name, int salary) {
super();
this.id = id;
this.name = name;
this.salary = salary;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
System.out.println("Employee.getName()");
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
}
In database there is a record with id 123.
Now my question is why the first level cache is not cleared??
EclipseLink has a shared object (2nd level) cache which is enabled by default and which:
...exists for the duration of the persistence unit (EntityManagerFactory,
or server) and is shared by all EntityManagers and users of the
persistence unit.
If you disable this according to the instructions in the below then you should see the 2nd query firing.
https://wiki.eclipse.org/EclipseLink/Examples/JPA/Caching

JPA query returning duplicated values

I have a jpa query that should return 4 rows, and it does return 4 rows, but only the first 2 rows of the result are ok, the next 2 are the first row repeated. And no, the first row is not repeated in the database.
this is my query:
public static List<DetalleProcesosEntity> getALLbyid(int id_proceso){
Query q = entityManager.createQuery("select a from DetalleProcesosEntity a where a.idProceso=:id_proceso");
q.setParameter("id_proceso", id_proceso);
List<DetalleProcesosEntity>resultado=q.getResultList();
List<DetalleProcesosEntity>result=new ArrayList<DetalleProcesosEntity>(resultado);
return result;
}
what im doing is:
from a view called "procesos" wich contains a table i click in any of the "procesos" in the table and i go to its details (passing the "proceso" ID as a parameter):
this is the details backing bean:
#ManagedBean(name = "det_procesos")
#ViewScoped
public class DetalleProcesosBean {
private int idProceso;
private List<DetalleProcesosEntity>detalles;
#PostConstruct
public void init(){
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
//Obtener parametros del request
Map<String, String> parameterMap = externalContext.getRequestParameterMap();
idProceso = Integer.parseInt(parameterMap.get("id_proc"));
detalles= Procesos.getALLbyid(idProceso);
}
public List<DetalleProcesosEntity> getDetalles() {
return detalles;
}
public void setDetalles(List<DetalleProcesosEntity> detalles) {
this.detalles = detalles;
}
public int getIdProceso() {
return idProceso;
}
public void setIdProceso(int idProceso) {
this.idProceso = idProceso;
}
}
if i use distinct in the query it does not make any difference, i just get 2 rows and im sure in the database there are 4 rows with the same "id proceso" and different values.
I solved it.. it was because i was working with views and i did not setted a proper ID to one of them (i had to add #Id to one of attributes of the entity)

EclipseLink native query result into POJO - Missing descriptor for [Class]

I'm using EclipseLink to run some Native SQL. I need to return the data into a POJO. I followed the instructions at EclipseLink Docs, but I receive the error Missing descriptor for [Class]
The query columns have been named to match the member variables of the POJO. Do I need to do some additional mapping?
POJO:
public class AnnouncementRecipientsFlattenedDTO {
private BigDecimal announcementId;
private String recipientAddress;
private String type;
public AnnouncementRecipientsFlattenedDTO() {
super();
}
public AnnouncementRecipientsFlattenedDTO(BigDecimal announcementId, String recipientAddress, String type) {
super();
this.announcementId = announcementId;
this.recipientAddress = recipientAddress;
this.type = type;
}
... Getters/Setters
Entity Manager call:
public List<AnnouncementRecipientsFlattenedDTO> getNormalizedRecipientsForAnnouncement(int announcementId) {
Query query = em.createNamedQuery(AnnouncementDeliveryLog.FIND_NORMALIZED_RECIPIENTS_FOR_ANNOUNCEMENT, AnnouncementRecipientsFlattenedDTO.class);
query.setParameter(1, announcementId);
return query.getResultList();
}
I found out you can put the results of a Native Query execution into a List of Arrays that hold Objects. Then one can iterate over the list and Array elements and build the desired Entity objects.
List<Object[]> rawResultList;
Query query =
em.createNamedQuery(AnnouncementDeliveryLog.FIND_NORMALIZED_RECIPIENTS_FOR_ANNOUNCEMENT);
rawResultList = query.getResultList();
for (Object[] resultElement : rawResultList) {
AnnouncementDeliveryLog adl = new AnnouncementDeliveryLog(getAnnouncementById(announcementId), (String)resultElement[1], (String)resultElement[2], "TO_SEND");
persistAnnouncementDeliveryLog(adl);
}
You can only use native SQL queries with a class if the class is mapped. You need to define the AnnouncementRecipientsFlattenedDTO class as an #Entity.
Otherwise just create the native query with only the SQL and get an array of the data back and construct your DTO yourself using the data.
Old question but may be following solution will help someone else.
Suppose you want to return a list of columns, data type and data length for a given table in Oracle. I have written below a native sample query for this:
private static final String TABLE_COLUMNS = "select utc.COLUMN_NAME, utc.DATA_TYPE, utc.DATA_LENGTH "
+ "from user_tab_columns utc "
+ "where utc.table_name = ? "
+ "order by utc.column_name asc";
Now the requirement is to construct a list of POJO from the result of above query.
Define TableColumn entity class as below:
#Entity
public class TableColumn implements Serializable {
#Id
#Column(name = "COLUMN_NAME")
private String columnName;
#Column(name = "DATA_TYPE")
private String dataType;
#Column(name = "DATA_LENGTH")
private int dataLength;
public String getColumnName() {
return columnName;
}
public void setColumnName(String columnName) {
this.columnName = columnName;
}
public String getDataType() {
return dataType;
}
public void setDataType(String dataType) {
this.dataType = dataType;
}
public int getDataLength() {
return dataLength;
}
public void setDataLength(int dataLength) {
this.dataLength = dataLength;
}
public TableColumn(String columnName, String dataType, int dataLength) {
this.columnName = columnName;
this.dataType = dataType;
this.dataLength = dataLength;
}
public TableColumn(String columnName) {
this.columnName = columnName;
}
public TableColumn() {
}
#Override
public int hashCode() {
int hash = 0;
hash += (columnName != null ? columnName.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
if (!(object instanceof TableColumn)) {
return false;
}
TableColumn other = (TableColumn) object;
if ((this.columnName == null && other.columnName != null) || (this.columnName != null && !this.columnName.equals(other.columnName))) {
return false;
}
return true;
}
#Override
public String toString() {
return getColumnName();
}
}
Now we are ready to construct a list of POJO. Use the sample code below to construct get your result as List of POJOs.
public List<TableColumn> findTableColumns(String table) {
List<TableColumn> listTables = new ArrayList<>();
EntityManager em = emf.createEntityManager();
Query q = em.createNativeQuery(TABLE_COLUMNS, TableColumn.class).setParameter(1, table);
listTables = q.getResultList();
em.close();
return listTables;
}
Also, don't forget to add in your POJO class in persistence.xml! It can be easy to overlook if you are used to your IDE managing that file for you.
Had the same kind of problem where I wanted to return a List of POJOs, and really just POJOs (call it DTO if you want) and not #Entity annotated Objects.
class PojoExample {
String name;
#Enumerated(EnumType.STRING)
SomeEnum type;
public PojoExample(String name, SomeEnum type) {
this.name = name;
this.type = type;
}
}
With the following Query:
String query = "SELECT b.name, a.newtype as type FROM tablea a, tableb b where a.tableb_id = b_id";
Query query = getEntityManager().createNativeQuery(query, "PojoExample");
#SuppressWarnings("unchecked")
List<PojoExample> data = query.getResultList();
Creates the PojoExample from the database without the need for an Entity annotation on PojoExample. You can find the method call in the Oracle Docs here.
edit:
As it turns out you have to use #SqlResultSetMapping for this to work, otherwise your query.getResultList() returns a List of Object.
#SqlResultSetMapping(name = "PojoExample",
classes = #ConstructorResult(columns = {
#ColumnResult(name = "name", type = String.class),
#ColumnResult(name = "type", type = String.class)
},
targetClass = PojoExample.class)
)
Just put this anywhere under your #Entity annotation (so in this example either in tablea or tableb because PojoExample has no #Entity annotation)

Creating an "IN" query with JPA 2.0 Criteria api

I am using tje JPA criteria API to create an "IN" query. I want to select Courses that are in certain Categories. The Categories are supposed to end up in the IN part of the query.
This is the Course entity. It has a reference to a Category entity, because each Course is in one Category.
#Entity
public class Course implements DomainObject {
private Long id;
private Integer version;
private String name;
private Category category;
#Override
#Id
#GeneratedValue
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#ManyToOne
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getVersion() {
return version;
}
public void setVersion(Integer version) {
this.version = version;
}
}
In my service I want to select Courses that are belong to certain (a list) of Categories.
public List<Course> findCourses(CourseFilter filter) {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Course> criteriaQuery = criteriaBuilder.createQuery(Course.class);
Root<Course> root = criteriaQuery.from(Course.class);
List<Predicate> predicateList = new ArrayList<Predicate>();
if (!filter.getCategories().isEmpty()) {
Predicate predicate = root.get(Course_.category).in(filter.getCategories());
predicateList.add(predicate);
}
Predicate[] predicates = new Predicate[predicateList.size()];
predicateList.toArray(predicates);
criteriaQuery.where(predicates);
TypedQuery<Course> typedQuery = entityManager.createQuery(criteriaQuery);
return typedQuery.getResultList();
}
When the query executes on the last line of the method it throws an error:
HTTP Status 500 - Request processing failed; nested exception is
org.springframework.dao.InvalidDataAccessApiUsageException:
org.hibernate.TransientObjectException: object references an unsaved transient instance
save the transient instance before flushing:nl.codebasesoftware.produx.domain.Category;
nested exception is java.lang.IllegalStateException:
org.hibernate.TransientObjectException: object references an unsaved transient instance
save the transient instance before flushing: nl.codebasesoftware.produx.domain.Category
I am not even sure I am using the right way to create an IN query. I think the criteria API is terribly complicated. But before I worry about the IN query I would like to know why Hibernate is throwing this TransientObjectException. The filter.getCategories() call results in actual categories, filled with a primary key id, etc.
Added:
Here is how I get the Category instance that I use to later fetch Courses with. This is also a DAO method that is called via a #Service from a #Controller method.
public Category findByName(String name) {
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Category> query = builder.createQuery(Category.class);
Root<Category> root = query.from(Category.class);
Predicate predicate = builder.equal(root.get(Category_.urlTitle), name);
query.where(predicate);
TypedQuery<Category> typedQuery = entityManager.createQuery(query);
return getSingleResult(typedQuery);
}
So, Hibernate is telling me I am using Category objects that somehow reference an unsaved entity, but I don't see how. The Category that is returned from this method is just a Category that if fetched by Hibernate. I am not doing anything with it before I send it to the method that fetches Courses.
Here is my the controller method:
#RequestMapping(method = RequestMethod.GET, value = "/{categoryUrlName}")
public String setup(#PathVariable("categoryUrlName") String categoryUrlName, Model model){
// Fetch the category
Category category = categoryService.findByName(categoryUrlName);
// if no category found, throw a 404
if(category == null){
throw new ResourceNotFoundException();
}
// Fetch courses in this category
List<Course> courses = courseService.findCourses(category);
model.addAttribute("courses", courses);
model.addAttribute("category", category);
model.addAttribute("mainContent", "content/category");
return "main";
}
Before executing a query, Hibernate flushes the changes you made to persistent entities in the session. This ensures that the query will search on the latest state of all the entities. Unfortunately, one of the dirty entities that Hibernate tries to flush references a transient entity, and thus can't be flushed, which causes the exception. The exception doesn't come from the query itself, but from the flush before the execution of the query.
You probably did something like the following before executing the query:
Cat cat = em.find(Cat.class, catId); // cat is a persistent persistent entity
cat.setMate(new Mouse()); // the mouse has not been persisted, and cat references it.

JPA composite PK is not working with 'finder' in play framework

I have a model called 'UserRoleHolder' like below.
#Entity
public class UserRoleHolder extends Model implements RoleHolder {
private static final long serialVersionUID = 1L;
#EmbeddedId
public UserRoleHolderPK userRoleHolderPK;
public List<UserPermission> permissions;
public List<UserRole> roles;
....
I made a composite PK called UserRoleHolderPK and it contains two foreign keys like below.
#Embeddable
public class UserRoleHolderPK {
#Basic
public Long userId;
#Basic
public Long projectId;
public UserRoleHolderPK(Long userId, Long projectId) {
this.userId = userId;
this.projectId = projectId;
}
public boolean equals(Object object) {
if (object instanceof UserRoleHolderPK) {
UserRoleHolderPK userRoleHolderPK = (UserRoleHolderPK) object;
return userId == userRoleHolderPK.userId && projectId == userRoleHolderPK.projectId;
} else {
return false;
}
}
public int hashCode() {
return (int) (userId + projectId);
}
}
userId and projectId are from other Models. (User.java and Project.java)
Then, in 'UserRoleHolder' class, I made a method called 'findRolesById' like below.
public static List<? extends Role> findRolesById(Long userId, Long projectId) {
return find
.where()
.eq("userRoleHolderPK", new UserRoleHolderPK(userId, projectId))
.findUnique().roles;
}
However, when I tried to run a test code like below, I encountered serious errors.
#Test
public void findRolesById() {
// Given
// When
#SuppressWarnings("unchecked")
List<UserRole> list = (List<UserRole>) UserRoleHolder.findRolesById(1l, 1l);
// Then
assertThat(list.get(0).name).isEqualTo("manager");
}
Errors are like,
'Syntax error in SQL statement "SELECT T0.USER_ID C0, T0.PROJECT_ID C1 FROM USER_ROLE_HOLDER T0 WHERE T0.NULL[*] = ? "; expected "identifier"; SQL statement: select t0.user_id c0, t0.project_id c1 from user_role_holder t0 where t0.null = ? [42001-158]
Bind values:[null]
Query was:
select t0.user_id c0, t0.project_id c1 from user_role_holder t0 where t0.null = ?
I think I missed some serious and basic stuff when I used JPA. Please, let me know what is the problem.
I think your problem is that you are trying to compare the Embeddedid object and not its fields, I don't think that the program will be smart enough as to know how to convert an user object comparison (the equals) to sql, so you might want to try something like this:
public static List<? extends Role> findRolesById(Long userId, Long projectId) {
return find
.where()
.eq("userRoleHolderPK.userId", userId)
.eq("userRoleHolderPK.projectId", projectId)
.findUnique().roles;
}