I am working on project using java playframework 1.2.4 and I have a #Entity class. It is look like
#Entity
public class EmployeeType extends Model {
public static enum TYPE { HOURLY, DAILY, MONTHLY };
public static enum NATIONALITY { LOCAL, FOREIGN };
#Required
#Enumerated(EnumType.STRING)
public TYPE type;
#Required
#Enumerated(EnumType.STRING)
public NATIONALITY nationality;
}
And in my controller class I want to get list of EmployeeTypes using my 2 enum attributes.
Query looks like
Query query = JPA.em().createQuery("SELECT e FROM EmployeeType e where " +
"e.nationality = :nationality " +
"and e.type = :type");
query.setParameter("nationality", NATIONALITY.LOCAL);
query.setParameter("type", TYPE.HOURLY);
List<models.EmployeeType> employeeType = query.getResultList()
Gives this error: IllegalArgumentException occured : Parameter value [LOCAL] was not matching type [models.EmployeeType$NATIONALITY]
What should i do?
The error is possibly because of the fact that your enums are nested in your entity. You need to access it on entity name.
You can change your setParameter code to: -
query.setParameter("nationality", EmployeeType.NATIONALITY.LOCAL);
query.setParameter("type", EmployeeType.TYPE.HOURLY);
Related
Is it possible to use JpaRepository without entity? In this case, replacing it with a DTO.
as follows the example
#Repository
public interface BffRepository extends JpaRepository<BffDTO, String> {
#Query(nativeQuery = true, value = "select\n"
+ "ent.name as enterprise_name, dep.name as department_name,\n"
+ "sq.name as squad_name, acc.firstname as job_owner_name,\n"
+ "tpt.name as test_template_name, job.name, job.job_blocked, job.job_removed,\n"
+ "job.bot_scm_branch, job.bot_scm_url, job.schedule_startdate,\n"
+ "job.expiration_date, job.timestamp,job.uuid,job.schedule_starttime,\n"
+ "tpt.job_execution_timeout\n"
+ "from portal.jobs job\n"
+ "left join portal.enterprises ent on (ent.uuid = job.enterprise_id)\n"
+ "left join portal.departments dep on (dep.uuid = job.department_id)\n"
+ "left join portal.squads sq on (sq.uuid = job.squad_id)\n"
+ "left join portal.accounts acc on (acc.uuid = job.job_owner)\n"
+ "left join portal.test_plan_templates tpt on (tpt.uuid = job.template_id) where\n"
+ "job.job_owner = ?1 and job.job_removed = false order by timestamp desc;")
List<BffDTO>buscarPorJobOwner(String jobOwner);
Are there alternatives for this case?
NOTE: the DTO is already mapped, but I would not like to create a view to transform this DTO into an Entity.
I already validated this topic, but without major advances
Use JpaRepository interaction style without entity
i'm trying this
Interface -
public interface BffDTOInterface2 {
String uuid();
String enterprise_name();
String department_name();
String squad_name();
String job_owner_name();
String test_template_name();
String name();
Boolean job_blocked();
Boolean job_removed();
String bot_scm_branch();
String bot_scm_url();
String schedule_startdate();
String expiration_date();
String timestamp();
String schedule_starttime();
Integer job_execution_timeout();
#Transient
String status();
}
I'm having this error
Caused by: java.lang.IllegalArgumentException: Not a managed type: interface br.com.cloud.api.domain.dto.BffDTOInterface2
You can use Projections based on interfaces.
e.g
Create your native-query givin it column a alias. select name as fullName, age as age from person.
Create a Interface that represents your DTO with get-methods to every alias of your native query.
interface MyDTO {
String getFullName();
Integer getAge();
}
The return type of your query now can be this MyDTO
#Query(value = "select name as fullName, age as age from person", nativeQuery=true)
List<MyDTO> findMyDTO();
Is it possible to use JpaRepository without entity?
No, it is not, and it would completely defeat the purpose of JPA, by definition.
JPA is the persistence specification that enables ORM - Object Relational Mapping - that is, you map Java objects to database tables' entries/rows, and Java types to database tables, respectively.
DTO (Data Transfer Object) has nothing to do with ORM, and it serves different purpose (I recommend you to read this article for DTO vs. Entity matter) - transferring data through Java objects - and it usually serves the middle layer, for converting persistent objects(#Entitys) into objects to be used in the web layer (DTOs), and vice versa.
If you really want to avoid persistence layer models (#Entitys), you may go for JDBC abstractions (e.g. Spring Data JDBC), native queries, JPQL, HQL, or a bare JDBC API (which I wouldn't recommend).
but you can try this.
What you can do is you can create your own custom repository class. First, you would have some service class that calls repository class. also notice that we have custom models for the result set of SQL queries.
#Service
public class CustomService {
#Autowired
private CustomRepository repository;
public List<CustomResponse> getAllResult(String id) {
List<Object[]> items = repository.getAllResult(id);
List<CustomResponse> customResponseList = new ArrayList();
for (Object[] item: items) {
CustomResponse c = new CustomResponse();
c.setTestValue1(String.valueOf(item[0]));
c.setTestValue2(String.valueOf(item[1]));
customResponseList.add(c);
}
return customResponseList;
}
}
and your repository class will be look like this.
#Repository
public class CustomRepository {
#Autowired
private EntityManager entityManager;
public List<Object[]> getAllResult(String id) {
Query q = (Query) entityManager.createNativeQuery("SELECT\n" +
" users.user_id as user_id,\n" +
" users.email as user_email\n" +
" FROM Users\n" +
" WHERE users.parent_id = :parent_id;");
q.setParameter("parent_id", id);
List<Object[]> results = q.getResultList();
return results;
}
}
Also you might want to have your own model for that. (like entities)
public class CustomResponse {
private String testValue1;
private String testValue2;
public String getTestValue1() {
return testValue1;
}
public void setTestValue1(String testValue1) {
this.testValue1 = testValue1;
}
public String getTestValue2() {
return testValue2;
}
public void setTestValue2(String testValue2) {
this.testValue2 = testValue2;
}
}
This is possible.
Define base entity and have one column. If you dont want this to exist in database, turn off ddl-auto in application.propeties.
spring.jpa.hibernate.ddl-auto=none
#Entity
#Data
public class BaseEntity {
#Id
private Long id;
}
and use any custom query with any other dao extending jpa repository with BaseEntity.
public interface EmployeeDao extends JpaRepository<BaseEntity, Long> {
#Query(value = "select name from employee where employee_number = ?", nativeQuery = true)
Optional<Employee> get(String employeeNumber);
}
public interface Employee{
String getName();
}
I have a Converter to convert the String stored in the DB to the corresponding Enum element:
#Converter(autoApply=true)
public class DokumentTypConverter implements AttributeConverter<DokumentTypSchluessel, String> {
#Override
public String convertToDatabaseColumn(DokumentTypSchluessel attribute) {
return attribute.getValue();
}
#Override
public DokumentTypSchluessel convertToEntityAttribute(String dbData) {
return DokumentTypSchluessel.from(dbData);
}
}
I have an Entity class which has a field of the Enum type:
#Entity
#Table(name="REF_DOKUMENTTYPEN")
public class DokumentTyp {
private DokumentTypSchluessel schluessel;
// snip
}
Now when I try to retrieve an instance of that entity from the db
String query = "SELECT d FROM DokumentTyp d WHERE d.schluessel = " + VORBEREITUNG;
entityManager.createQuery(query, DokumentTyp.class).getSingleResult();
I get the following error:
javax.persistence.PersistenceException: An exception occurred while calling convertToDatabaseColumn on converter class de.drvbund.pub.model.convert.DokumentTypConverter with value VORBEREITUNG
at org.eclipse.persistence.mappings.converters.ConverterClass.convertObjectValueToDataValue(ConverterClass.java:139)
at org.eclipse.persistence.mappings.foundation.AbstractDirectMapping.getFieldValue(AbstractDirectMapping.java:778)
at org.eclipse.persistence.internal.expressions.QueryKeyExpression.getFieldValue(QueryKeyExpression.java:420)
at org.eclipse.persistence.internal.expressions.ConstantExpression.printSQL(ConstantExpression.java:152)
at org.eclipse.persistence.expressions.ExpressionOperator.printDuo(ExpressionOperator.java:2241)
at org.eclipse.persistence.internal.expressions.CompoundExpression.printSQL(CompoundExpression.java:286)
at org.eclipse.persistence.internal.expressions.RelationExpression.printSQL(RelationExpression.java:899)
at org.eclipse.persistence.internal.expressions.ExpressionSQLPrinter.translateExpression(ExpressionSQLPrinter.java:325)
at org.eclipse.persistence.internal.expressions.ExpressionSQLPrinter.printExpression(ExpressionSQLPrinter.java:129)
at org.eclipse.persistence.internal.expressions.SQLSelectStatement.printSQL(SQLSelectStatement.java:1755)
at org.eclipse.persistence.internal.databaseaccess.DatabasePlatform.printSQLSelectStatement(DatabasePlatform.java:3268)
at org.eclipse.persistence.platform.database.OraclePlatform.printSQLSelectStatement(OraclePlatform.java:967)
at org.eclipse.persistence.internal.expressions.SQLSelectStatement.buildCall(SQLSelectStatement.java:843)
at org.eclipse.persistence.internal.expressions.SQLSelectStatement.buildCall(SQLSelectStatement.java:854)
at org.eclipse.persistence.descriptors.ClassDescriptor.buildCallFromStatement(ClassDescriptor.java:815)
at org.eclipse.persistence.internal.queries.StatementQueryMechanism.setCallFromStatement(StatementQueryMechanism.java:390)
at org.eclipse.persistence.internal.queries.StatementQueryMechanism.prepareSelectAllRows(StatementQueryMechanism.java:315)
at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.prepareSelectAllRows(ExpressionQueryMechanism.java:1723)
at org.eclipse.persistence.queries.ReadAllQuery.prepareSelectAllRows(ReadAllQuery.java:904)
at org.eclipse.persistence.queries.ReadAllQuery.prepare(ReadAllQuery.java:835)
at org.eclipse.persistence.queries.DatabaseQuery.checkPrepare(DatabaseQuery.java:673)
... 151 more
Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to de.drvbund.pub.enums.DokumentTypSchluessel
I guess the framework takes the toString()-representation of the Enum element from the query, assumes it is the entity attribute value, that needs to be converted to its corresponding dbValue and tries to call the convertToDatabaseColumn() method passing the String. I just don't know how to do this correctly.
How can I retrieve entities filtered by an Enum attribute value with JPA?
The problem was solved by the suggestion of Chris:
entityManager.createQuery("SELECT d FROM DokumentTyp d WHERE d.schluessel = ?1", DokumentTyp.class)
.setParameter(1, DokumentTypSchluessel.VORBEREITUNG)
.getSingleResult();
I am using jdk 1.8 , hibernate and jpa in my project. And using specification/criteria to build my search query.
I have a class A ( an hibernate entity) which has class B as an attribute. So, roughly, it looks like :
#Entity
class A {
Long id;
String comment;
#OneToOne
B b;
}
and...
#Entity
class B {
Long id;
String type;
}
My repository class looks like (roughly):
public interface ARepository extends PagingAndSortingRepository<A, Integer>,
JpaSpecificationExecutor<A> {
}
Most of the simple JPA queries are working as expected. Even the specification/criteria based directly on Class A is working. However, I need to create a dynamic query and that should be executed under "findAll" method of PagingAndSortingRepository class. This query should be equivalent to
select * from A a left join B b on a.b_id = b.id
where b.type='final' and a.comment='blah';
I created a similar logic as above in a specification like :
public Specification<A> getSpecification() {
return (itemRoot, query, criteriaBuilder) -> {
.........
List<Predicate> partialQueries = new ArrayList<>();
partialQueries.add(criteriaBuilder.equal(itemRoot.get("b.type"), "final"));
partialQueries.add(criteriaBuilder.equal(itemRoot.get("comment"), "blah"));
//Other queries to be added...
return criteriaBuilder.and(partialQueries.toArray(new Predicate[0]));
};
}
And getting error :
Unable to locate Attribute with the the given name [b.type] on this ManagedType [com.something.domain.A]
Any insight on how to create criteria/specification on a field that belongs to a nested object?
If you want to filter nested object. You can write
itemRoot.get("NestedTableName").get("nestedfieldname")
In your case - itemRoot.get("B").get("type")
itemRoot.get("Name of the nested object field in the root class").get("nestedfieldname");
Example:
cb.equal(root.get("b").get("type"),value)
In your case - itemRoot.get("b").get("type");
I have an Enum class which has some values.
We've decided to remove one of these values and its all implementation from the code.
We dont want to delete any records from DB.
My Enum class is something like this:
public enum CourseType {
VIDEO("CourseType.VIDEO"),
PDF("CourseType.PDF"),
QUIZ("CourseType.QUIZ"),
SURVEY("CourseType.SURVEY"),
POWERPOINT("CourseType.POWERPOINT") //*this one will be removed*
...
}
My Course Entity:
#Entity
#Table(name = "CRS")
public class Course {
#Column(name = "COURSE_TYPE")
#Enumerated(EnumType.STRING)
private CourseType courseType;
#Column(name = "AUTHOR")
private String author;
....
#Override
public CourseType getCourseType() {
return courseType;
}
#Override
public void setCourseType(CourseType courseType) {
this.courseType = courseType;
}
....
}
After I removed the Powerpoint type from the Java Class and tried to fetch some values from the DB,
I get a mapping error for the removed type.
I have a code like this:
Course course = courseService.get(id);
If I gave a course id which its type is 'POWERPOINT' in the database,
the method gets the following error:
java.lang.IllegalArgumentException: Unknown name value [POWERPOINT]
for enum class [com.tst.enums.CourseType] at
org.hibernate.type.EnumType$NamedEnumValueMapper.fromName(EnumType.java:461)
at
org.hibernate.type.EnumType$NamedEnumValueMapper.getValue(EnumType.java:449)
at org.hibernate.type.EnumType.nullSafeGet(EnumType.java:107) at
org.hibernate.type.CustomType.nullSafeGet(CustomType.java:127) at
org.hibernate.type.AbstractType.hydrate(AbstractType.java:106) at
org.hibernate.persister.entity.AbstractEntityPersister.hydrate(AbstractEntityPersister.java:2912)
at org.hibernate.loader.Loader.loadFromResultSet(Loader.java:1673)
Is there any way when I try to retrieve a query result from DB,
hibernate will not fetch if that records' course_type column doesn't match with the any of the enum values in the code?
Do I have to use some kind of filter?
You can try use annotation #filter
#Filter(name = "myFilter", condition = "courseType <> 'CourseType.POWERPOINT'")
and enable it
session.enableFilter("myFilter")
If you can't use filters,
something like the following should work:
Add POWERPOINT back into the enum.
Add a deleted flag to the POWERPOINT enum value.
After the course list is loaded, remove courses that have a deleted courseType value.
New CourseType enum:
public enum CourseType
{
VIDEO("CourseType.VIDEO", false),
POWERPOINT("CourseType.POWERPOINT", true);
private boolean deletedFlag;
public CourseType(
existingParameter, // do whatever you are currently doing with this parameter
deletedFlagValue)
{
// code to handle existing parameter
deletedFlag = deletedFlagValue;
}
I am using Spring + Hibernate and I have a particular case where I need to obtain (a list of) non-Entity objects as a result of the query.
I decided to use #ConstructorResult in #SqlResultSetMapping and refer to this mapping in #NamedNativeQuery, as mentioned here and here.
However, in all examples using named native queries, they obtain EntityManager instance via #PersistenceContext and call createNativeQuery on it, providing the name of #NamedNativeQuery as parameter to that call, as seen in this answer.
How can I map a method declared in a repository interface to a particular #NamedNativeQuery? My attempt was to use EntityName.MethodNameInRepository or MethodNameInRepository as the name of #NamedNativeQuery, but no luck.
Here is my simplified code:
#Entity(name = "AdDailyData")
#SqlResultSetMapping(
name="RevenueByAppAndDayMapping",
classes=#ConstructorResult(
targetClass=RevenueByAppAndDay.class,
columns={#ColumnResult(name="country_code"),
#ColumnResult(name="revenue", type=Double.class),
#ColumnResult(name="currency")}))
#NamedNativeQuery(
name="AdDailyData.aggregateRevenue",
query="SELECT country_code, sum(earnings) as revenue, currency "
+ "FROM ad_daily_data, pseudo_app, app "
+ "WHERE ad_daily_data.pseudo_app_id=pseudo_app.id AND pseudo_app.app_id=app.id AND app.id=:appId and ad_daily_data.day = :day "
+ "GROUP BY country_code, currency "
+ "ORDER BY country_code ASC",
resultSetMapping="RevenueByAppAndDayMapping")
public class AdDailyDataEntity {
// fields, getters, setters etc.
public static interface Repository extends JpaRepository<AdDailyDataEntity, Long> {
public List<RevenueByAppAndDay> aggregateRevenue(#Param("appId") long appId, #Param("day") LocalDate day);
}
}
Here is my non-Entity class.
public class RevenueByAppAndDay {
private String countryCode;
private Double earnings;
private String currency;
public RevenueByAppAndDay(String countryCode, Double earnings, String currency) {
this.countryCode = countryCode;
this.earnings = earnings;
this.currency = currency;
}
public String getCountryCode() {
return countryCode;
}
public Double getEarnings() {
return earnings;
}
public String getCurrency() {
return currency;
}
}
Any kind of help is highly appreciated.
EDIT:
The end of the stack trace is as follows:
Caused by: org.springframework.data.mapping.PropertyReferenceException: No property aggregateRevenue found for type AdDailyDataEntity!
The name value on the #NamedNativeQuery needs to be set to "AdDailyDataEntity.aggregateRevenue". The first part (before the dot) needs to match the entity class name.
Although the answer is correct, for someone to arrived here for similar cuestions this works for me without used #NamedNativeQuery:
public class Example {
private Long someProperty;
// getters and setters
}
To call a query or stored procedure and populate my object:
#Repository
public interface ExampleRepository extends
JpaRepository<Example,Long> {
/**
* Search Example by someProperty
*
* #param property
* #return
*/
#Query( nativeQuery = true, value = "SELECT * FROM public.my_stored_procedure(:property)")
List<Example> findByProperty(#Param("property") Long property);
}
I know this is another approach and the code is decoupled, but we get the same result.
I hope that can be useful for someone.
Regards.