How to use enum in #Query as a constant - spring-data-jpa

I have tried to put a full class path (com.xxxx.State.Finish) after != but not helping.
#Query("select c from CustomOrder c where c.dealer = :roleName and
c.nextManager = null and c.currentState != Finish")
List<CustomOrder> findOpenOrder(#Param("roleName") String roleName);
Entity:
#Getter
#Enumerated(EnumType.STRING)
CustomOrderEnums.State currentState;
Enum:
public enum State {
Open, Finish
}

#Query("select c from CustomOrder c where c.dealer = :roleName and
c.nextManager = null and c.currentState != com.xxx.FooEnum.Finish")
FooEnum has to be a top class not an inner one. If it has to be an inner class, use ' quoted string (haven't tried it without ').
#Query("select c from CustomOrder c where c.dealer = :roleName and
c.nextManager = null and c.currentState != 'Finish'")
I have just found that instead of using #Query it could be simply used as:
List<User> findIdByRoleRoleAndProvinceType(String role, ProvinceEnum.ProvinceType provinceType);
and this is entity User:
#Entity
public class User {
Role role; // entity has a String field role;
Province province; // entity has a ProvinceEnum.ProvinceType field type.
...
}

Related

JPA basic type ElementCollection computed value in query

Consider the following Entity :
#Entity
public class Parent{
#Column
private String name;
#ElementCollection
#CollectionTable(name="REF_TABLE",joinColumns=#JoinColumn(name="REF_COLUMN_ID"))
#Column(name="REF_COLUMN_VALUE")
public Set<String> getValues() {
return values;
}
}
I need to implement JPA criteria where clause for "UPPER(REF_COLUMN_VALUE) IN (?values)"
So far I have :
root.joinSet(Parent_.values, JoinType.LEFT).in(collectionOfValues)
How can I apply UPPER function for each element in values ?
I know I can achieve this by defining and wrapping String value as #Embeddable class, that would give me meta-attribute for value property and I could do :
joinSet = root.joinSet(Parent_.values, JoinType.LEFT);
criteriaBuilder.isMember(criteriaBuilder.upper(joinSet.get(WrapedString_.value)),criteriaBuilder.literal(collectionOfValues))
Can I do it without introducing the wrapper ?
Thanks
In case someone interested in :
SetJoin<Object, Object> setJoin = root.joinSet(Parent_.values.getName(), JoinType.LEFT);
CriteriaBuilder.In<String> in = criteriaBuilder.in(criteriaBuilder.upper(setJoin.as(String.class)));
for(String v:collectionOfValues){
in.value(v.toUpperCase());
}
Don't forget to add distinct to your query as LEFT_JOIN is being used.

Is there a way to transform objects that spring data repositories return?

Right now I have an entity object and a DTO. The repository returns a list of objects arrays when I do a simple example like: findById(). Is there a way to easily map the return type to be a custom DTO object rather than always return entity objects?
Example is below:
#Query("Select f.id, f.name from Food f where f.id = :id")
public List<Object[]> findById(#Param("id") String id);
My DTO object looks like:
FoodDto{
private String id;
private String name;
}
Right now I've only ever been able to get repositories to return a List< Object[] > type.
Try this.
#Query("Select new package.FoodDto(f.id, f.name) from Food f where f.id = :id")
public List<FoodDto> findById(#Param("id") String id);
Assuming class FoodDto is in package, if not you need to set the full package.
Also I assume the FoodDto have a constructor that match
public FoodDto(int id, String name){
//Variable assignation
}
I never tried in spring-jpa but that works in JPQL so I assume it will work XD

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)

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

Construct JPA query for a OneToMany relation

I've those 2 entities
Class A {
#OneToMany(mappedBy="a")
private List<B> bs;
}
Class B {
#ManyToOne
private A a;
private String name;
}
1) I would like to construct a query that says get all A's that have at least one B with name ="mohamede1945"
2) I would like to construct a query that says get all A's that don't have any B with name = "mohamede1945"
Could anyone help me?
First of all, I think you can learn the answer by looking at this link and search for JOIN: http://download.oracle.com/docs/cd/E11035_01/kodo41/full/html/ejb3_langref.html
Second of all, here is my approach:
#Entity
#NamedQueries({
#NamedQuery(name="A.hasBName",query="SELECT a FROM A a JOIN a.b b WHERE b.name = :name"),
#NamedQuery(name="A.dontHasBName",query="SELECT a FROM A a JOIN a.b b WHERE b.name <> :name")
})
Class A { /* as you defined */ }
In you DAO, you can make the namedquery like this:
public List<A> findByHasBName( String name ){
Query q = em.createNamedQuery("A.hasBName")
.setParameter("name", name);
try{
return ( (List<A>) q.getResultList());
} catch ( IndexOutOfBoundsException e){
return null;
}
}
You can use the ANY and ALL constructs to filter the subquery. So something like
1. FROM A aEntity WHERE 'mohamede1945' = ANY (SELECT bEntity.name FROM aEntity.bs bEntity)
2. FROM A aEntity WHERE 'mohamede1945' <> ALL (SELECT bEntity.name FROM aEntity.bs bEntity)