my class is:
#AllArgsConstructor
#NoArgsConstructor
public class RoleData {
#Column(name = "role_id")
private String roleId;
#Column(name = "use_mail_send")
private Boolean useMailSend;
#Column(name = "mail_send")
private Boolean mailSend;
#Column(name = "use_output")
private Boolean useOutput;
#Column(name = "possible_to_output")
private Boolean possibleToOutput;
#Column(name = "use_import")
private Boolean useImport;
#Column(name = "possible_to_import")
private Boolean possibleToImport;
}
my JPA native query is:
#Query(value = "select cast(r.role_id as text) as role_id, " +
" fm.use_mail_send, " +
" rd.mail_send, " +
" fm.use_output, " +
" rd.possible_to_output, " +
" fm.use_import, " +
" rd.possible_to_import " +
"from role_detail rd " +
" join role r on rd.role_id = r.role_id " +
" join feature_mst fm on fm.company_code = rd.company_code and fm.feature_code = rd.feature_code and " +
" fm.feature_category = r.feature_category " +
"where rd.role_id = :roleId", nativeQuery = true)
List<RoleData> getAllByRoleId(#Param("roleId") UUID roleId);
I see it can fetch data, but throw exception when convert it to my RoleData class:
org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap] to type [com.ecometrue.common.dto.responses.RoleData]
at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:322)
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:195)
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:175)
at org.springframework.data.repository.query.ResultProcessor$ProjectingConverter.convert(ResultProcessor.java:297)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.lambda$and$0(ResultProcessor.java:217)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:228)
at org.springframework.data.repository.query.ResultProcessor.processResult(ResultProcessor.java:156)
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:157)
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:142)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor$QueryMethodInvoker.invoke(QueryExecutorMethodInterceptor.java:195)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:152)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:130)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:80)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:367)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118)
I have google multiple resource, and see this bug report: https://github.com/spring-projects/spring-data-jpa/issues/1349?focusedCommentId=133359&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel
I found a solution, replace RoleData to Object in repository:
List<Object[]> getAllByRoleId(#Param("roleId") UUID roleId);
But i want to parse data to DTO object.
Annotations are missing. First of all you need #Entity annotation. Also you need to have a primary key defined in your table as each JPA entity must have a primary key which uniquely identifies it
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
You are missing getters and setters. Add #Data annotation on top of your class.
Update-Extra:
If you want to save data via that entity in pg, you need to create a sequence for that table. Also, add your primary key identifier as aang13 mentioned. Otherwise, without sequence, your primary key will not be incremented like MySQL db.
Related
In my project, in the repository, I have a select that displays all the data I need, including those months for which I don’t have data. To do this, in my select, I create a temporary column, which I named tneDate .
#Query(value = "SELECT \n" +
" theDate, asl.id, asl.interest_payment, asl.interest_rate, asl.principal_payment, asl.total_payment, asl.actual_delta, \n" +
" asl.date, asl.modified, asl.interest_payment_modified, asl.amortization_schedule_initial_id, asl.tranche_id, asl.outstanding_usd,\n" +
" asl.disbursement, asl.floating_index_rate, asl.upfront_fee, asl.commitment_fee, asl.other_fee, asl.withholding_tax, \n" +
" asl.default_fee, asl.prepayment_fee, asl.total_out_flows, asl.net_flows, asl.user_id, asl.outstanding_principal, asl.new_row\n" +
"FROM\n" +
" GENERATE_SERIES\n" +
" (\n" +
" (SELECT MIN(ams.date) FROM amortization_schedules ams),\n" +
" (SELECT MAX(ams.date) + INTERVAL '1' MONTH FROM amortization_schedules ams),\n" +
" '1 MONTH'\n" +
" ) AS tab (theDate)\n" +
"FULL JOIN amortization_schedules asl on to_char(theDate, 'yyyy-mm') = to_char(asl.date, 'yyyy-mm')", nativeQuery = true)
List<AmortizationSchedule> findAllByDate();
Now, through the getter in Entity , I want to get only this tneDate , that is, the date that I form. I don't want it to be written to the database. Therefore, I put the #Transient annotation, but as I understand it, this annotation ignores the getter of this entity and I cannot get this data, since I get NULL. In this part :
else {
BigDecimal swaprate = getRate(previousAmortiz.getDate(), previousAmortiz.getTranche().getLocalCurrency().getId());
childReports.add(createChild(previousAmortiz.getOutstandingPrincipal(), swaprate, previousAmortiz.getTheDate()));
My Entity
#Getter
#Setter
#ToString
#Entity
#Table(name = "amortization_schedules")
public class AmortizationSchedule {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Transient
private Date theDate;
#Column(name = //)
private BigDecimal //;
how do i get the tneDate data?
In my Spring boot application I have a query which should return a distinct List of Focus' (works perfectly in MySQL)
#Query(value = "SELECT DISTINCT * FROM Focus F " +
"JOIN FrameworkFoci FF on FF.focusID = F.focusID " +
"JOIN FocusGroups FG on FF.frameworkID = FG.frameworkID " +
"JOIN GroupMembers GM on FG.groupID = GM.groupID " +
"JOIN Users U on GM.userID = U.userID " +
"WHERE U.userID = :userID", nativeQuery = true)
List<Focus> findByUserID(#Param("userID") Long userID);
However this does not return distinct values, duplicates are contained in the resulting list. Another issue is that I can't return a whole entity using #Query annotation - changing my query to SELECT DISTINCT(F) FROM Focus F gives the error java.sql.SQLSyntaxErrorException: Unknown column 'F' in 'field list'.
Furthermore, I tried changing adjusting the query to the following
#Query(value = "SELECT DISTINCT * FROM FrameworkFoci FF " +
"JOIN FocusGroups FG on FF.frameworkID = FG.frameworkID " +
"JOIN GroupMembers GM on FG.groupID = GM.groupID " +
"JOIN Users U on GM.userID = U.userID " +
"WHERE U.userID = :userID", nativeQuery = true)
however this produced the error java.sql.SQLException: Column 'focusCategory' not found.
Why is the query not returning distinct values? And why can't I return a whole entity nor use the second query?
Focus Entity:
#Entity
public class Focus {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long focusID;
#Column(name = "focusCategory")
private String focusCategory;
private String focusName;
private String focusExplanation;
#OneToMany(mappedBy = "focus")
private Set<Rating> ratings;
#ManyToMany
#JoinTable(name = "FrameworkFoci",
joinColumns = #JoinColumn(
name = "focusID"),
inverseJoinColumns = #JoinColumn(
name = "frameworkID"))
private Set<Framework> frameworks;
//image
protected Focus(){}
public Focus(String focusName, String focusCategory, String focusExplanation) {
this.focusCategory = focusCategory;
this.focusName = focusName;
this.focusExplanation = focusExplanation;
}
public Focus(String focusCategory, String focusName, String focusExplanation, Set<Rating> ratings){
this.focusCategory = focusCategory;
this.focusName = focusName;
this.focusExplanation = focusExplanation;
this.ratings = ratings;
}
public Long getFocusId() {
return focusID;
}
public void setFocusId(Long focusID) {
this.focusID = focusID;
}
public String getFocusCategory() {
return focusCategory;
}
public void setFocusCategory(String focusCategory) {
this.focusCategory = focusCategory;
}
EDIT:
I've switched from SQL to JPQL with the following query:
#Query(value = "SELECT DISTINCT focus FROM Focus focus " +
"WHERE focus.frameworks.groups.groupMembers.user.userID =:userID ")
I now get an error org.hibernate.QueryException: illegal attempt to dereference collection [focus0_.focusID.frameworks] with element property reference [groups]
Framework entity:
#Entity
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,
property = "frameworkID")
public class Framework {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long frameworkID;
private String frameworkName;
#ManyToMany
#JoinTable(name = "FrameworkFoci",
joinColumns = #JoinColumn(
name = "frameworkID"),
inverseJoinColumns = #JoinColumn(
name = "focusID"))
private Set<Focus> frameworkFoci = new HashSet<>();
#OneToMany(mappedBy = "framework", fetch = FetchType.EAGER, cascade = CascadeType.REMOVE)
private Set<Group> groups;
public Framework(){}
The following query solves the issue
#Query(value = "SELECT DISTINCT focus FROM Focus focus " +
"JOIN focus.frameworks frameworks " +
"JOIN frameworks.groups groups " +
"JOIN groups.groupMembers groupMembers "+
"WHERE groupMembers.userID =:userID ")
List<Focus> findByUserID(#Param("userID") Long userID);
Frameworks and GroupMembers are collections and hence needed to be joined, otherwise illegal attempt to dereference collection [focus0_.focusID.frameworks] with element property reference [groups] was produced
you should write your query like this:
'
SELECT DISTINCT f FROM Focus F '
The problem stems from you using SQL by specifying nativeQuery = true. SQL doesn't know about entities, just tables.
Since you presumably have many FrameworkFoci rows (and rows in all the other tables) for each Focus row, each Focus row gets repeated for each matching row in FrameworkFoci. This kind of duplicates the Focus row but the resulting rows are still distinct, because they differ in the columns from the other tables.
And then each row gets turned into a Focus entity, probably with a single element in the framework set.
So therefore query doesn't so much return duplicate results as results split into multiple entities.
Fortunately the solution should be fairly simple: Use JPQL which should be perfectly possible, since you're using only simple joins.
The following should give you a start:
#Query(value = "SELECT DISTINCT * FROM Focus F " +
"WHERE F.framework.groupMembers.user.id=:userID")
List<Focus> findByUserID(#Param("userID") Long userID);
I created some reports for my system, and that report is made up of many tables. For this, I create a Domain class with an #Entity annotation and implement a JpaRepository repository, I'm using the native query with #Query, as shown below.
My problem is that for each domain class a table is being created by hibernate, how do I stop it?
My Domain class:
#Entity
#Immutable
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
#IdClass(WidgetDailyReportCompositeKey.class)
public class WidgetDailyReportDomain{
#Id
#Column(updatable = false, insertable = false)
private UUID id_construction;
#Id
#Column(updatable = false, insertable = false)
private String name;
#Id
#Column(updatable = false, insertable = false)
private Date dt_cost;
#Column(updatable = false, insertable = false)
private Double total;
}
My Repository:
public interface WidgetRepository extends JpaRepository<WidgetDailyReportDomain, UUID>{
#Query(value = " SELECT ct.id AS id_construction, " +
" ct.name, " +
" sm.dt_service AS dt_cost, " +
" sum(smi.nu_value * stiv.amount) AS total " +
" FROM service_measurement sm " +
" INNER JOIN service_measurement_item smi ON smi.id_service_measurement = sm.id " +
" INNER JOIN service s ON s.id = sm.id_service " +
" INNER JOIN service_type_item_service stiv ON stiv.id_service = sm.id_service " +
" AND stiv.id_service_type_item = smi.id_service_item " +
" INNER JOIN construction ct ON ct.id = s.id_construction " +
" WHERE s.id_construction IN ( " +
" select s.id_construction " +
" from service_measurement sm " +
" INNER JOIN service_measurement_item smi ON smi.id_service_measurement = sm.id " +
" INNER JOIN service s ON s.id = sm.id_service " +
" INNER JOIN service_type_item_service stiv ON stiv.id_service = sm.id_service " +
" AND stiv.id_service_type_item = smi.id_service_item " +
" INNER JOIN construction ct on ct.id = s.id_construction " +
" WHERE sm.dt_service BETWEEN :minDate AND :maxDate " +
" GROUP BY s.id_construction " +
" ORDER BY sum(smi.nu_value * stiv.value) DESC " +
" limit :limit " +
" ) " +
" AND sm.dt_service BETWEEN :minDate AND :maxDate " +
" GROUP BY ct.id, sm.dt_service " +
" HAVING sum(smi.nu_value * stiv.amount) > 0 " +
" ORDER BY sm.dt_service;", nativeQuery = true)
List<WidgetDailyReportDomain> findTopExpensiveConstruction(#Param("minDate") Date minDate, #Param("maxDate") Date maxDate, #Param("limit") int limit);
//....
Your WidgetDailyReportDomain is actually projection. You don't need to mark it as #Entity.
And your #Query could belong to any other really existing repository.
You can remove all the javax.persistence annotations like #Column, #Id, #Entity. These annotations represent properties of a table, which you seem to not want it to be.
Then you can use the WidgetDailyReportDomain object as a DTO to be your projection and not have it attached to the EntityManager:
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections.dtos
EDIT: Also, do not forget to build a constructor for that object so that Spring JPA loads the values into the object (like described on the documentation).
If you don't want to build a constructor, maybe you can change it into an interface and use it as your projection: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections.interfaces
It looks like you're using Spring due to the JpaRepository in your question.
If you're using Spring Boot, then you can add
spring:
jpa:
hibernate:
ddl-auto: none
to your application.yml file, or
spring.jpa.hibernate.ddl-auto=none
to your application.properties file.
If you're using a persistence.xml file, you could add a property to disable it there, too:
<property name="hibernate.hbm2ddl.auto" value="none"/>
Disabling the generation of the schema tables like this means that you'll have to make sure they're created by some other means before your application will work, though.
After #Zagarh answer, i did a lith of search about DTO, and i came up with a not very elegant solution, but that is working:
The Domain class :
public class WidgetDailyReportDomain{
private UUID id_construction;
private String name;
private Date dt_cost;
private Double total;
}
I have to create a custom result mapping, for the JPA be able of mapping de result, i use the annotation #SqlResultSetMapping. But for some reason she is only identify in a class that is annotated with # Entity. For not to get disorganized, i create a class exclusive to annotation with # SqlResultSetMapping, because i gona have a lot of mapping to do. The class looked like this:
#MappedSuperclass
#SqlResultSetMapping(
name = "widget_daily_mapping",
classes = {
#ConstructorResult(
targetClass = WidgetDailyReportDomain.class,
columns = {
#ColumnResult(name="id_construction", type = UUID.class),
#ColumnResult(name = "name", type = String.class),
#ColumnResult(name = "dt_cost", type = Date.class),
#ColumnResult(name = "total", type = Double.class)
}
)
}
)
public abstract class ResultSetMappingConfig {
}
And then i create a custom implementation of Jpa Repository
public interface WidgetRepositoryCustom {
List<WidgetDailyReportDomain> findTopExpensiveConstruction(Date minDate, Date maxDate, int limit);
}
#Repository
#Transactional(readOnly = true)
public class AR_serviceRepositoryImpl implements AR_serviceRepositoryCustom{
#PersistenceContext
private EntityManager em;
#Override
public List<AR_serviceDomain> getListOfService(UUID id_construction) {
Query query = em.createNativeQuery("
//Native Query Here...
", "widget_daily_mapping");// Put the result mapping Here
query.setParameter(1, id_construction //..Parameters Here);
return query.getResultList();
}
}
Ps: 1) If any one have a better solution please let me know. 2) Sorry for my english, i'm using google translate.
After searching a lot, I have a trouble to save timestamp data in PostgreSQL base using Spring JPA Hibernate.
Here my main table in PostgreSQL, it's a partitionning table :
CREATE TABLE public.archive_traffic_measure
(
measure_point_id integer NOT NULL,
measure_agregation_id integer NOT NULL,
measure_datetime timestamp without time zone NOT NULL,
measure_type_id integer NOT NULL,
any_flow integer,
f_any_flow smallint,
hgv_flow integer,
f_hgv_flow smallint,
occupation_rate smallint,
f_occupation_rate smallint,
average_speed smallint,
f_average_speed smallint,
CONSTRAINT pk_archive_traffic_measure PRIMARY KEY (measure_point_id, measure_agregation_id, measure_datetime, measure_type_id)
)
Here my main entity with spring JPA hibernate with #SQLInsert to suppress the check and don't have the problem with hibernate that no row is insert (because the row is insert in a child table) :
#Entity
#Table(name = "archive_traffic_measure")
#SQLInsert(sql = "INSERT INTO archive_traffic_measure (measure_point_id," +
"measure_agregation_id," +
"measure_datetime," +
"measure_type_id," +
"any_flow," +
"f_any_flow," +
"hgv_flow," +
"f_hgv_flow," +
"occupation_rate," +
"f_occupation_rate," +
"average_speed," +
"f_average_speed) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", check = ResultCheckStyle.NONE)
public class ArchiveTrafficMeasure implements Serializable {
#EmbeddedId
private ArchiveTrafficMeasureId id;
#Column(name = "any_flow")
private Integer anyFlow;
#Column(name = "f_any_flow")
private Integer F_AnyFlow;
#Column(name = "hgv_flow")
private Integer hgvFlow;
#Column(name = "f_hgv_flow")
private Integer F_hgvFlow;
#Column(name = "occupation_rate")
private Integer occupationRate;
#Column(name = "f_occupation_rate")
private Integer F_occupationRate;
#Column(name = "average_speed")
private Integer averageSpeed;
#Column(name = "f_average_speed")
private Integer F_averageSpeed;
}
And my id's entity with Spring JPA hibernate :
#Embeddable
#Table(name = "archive_traffic_measure")
public class ArchiveTrafficMeasureId implements Serializable {
#Column(name = "measure_point_id")
private int measurePointId;
#Column(name = "measure_agregation_id")
private int measureAgregationId;
#Column(name = "measure_datetime", columnDefinition = "timestamp without time zone")
#Temporal(TemporalType.TIMESTAMP)
private Date measureDateTime;
#Column(name = "measure_type_id")
private int measureType;
}
When I try to insert new data I have this error :
ERROR: column "measure_datetime" is of type timestamp without time zone but
expression is of type integer
The problem is the request be like :
INSERT INTO archive_traffic_measure VALUES (1,2,2018-04-18 17:00:00+01,1,40,null,null,null,null,null,null,null)
So the quote arount the timestamp is missing...
I have try to put the quote in the #SQLInsert "(?,?,'?',?,?,?,?,?,?,?,?,?)" but with that, I have the error :
The column's index is out of bound : 12, number of column : 11.
I have also try "(?,?,''?'',?,?,?,?,?,?,?,?,?)" with double quote
Or "(?,?,?::timestamp,?,?,?,?,?,?,?,?,?)" but nothing is working for far.
Can someone help me ? Thanks in advance.
First, add nullable = false for 'measure_datetime' column definition also remove composite key from #SQLInsert:
#SQLInsert(sql = "INSERT INTO archive_traffic_measure ("any_flow," +
"f_any_flow," +
"hgv_flow," +
"f_hgv_flow," +
"occupation_rate," +
"f_occupation_rate," +
"average_speed," +
"f_average_speed) VALUES (?,?,?,?,?,?,?,?,?)", check = ResultCheckStyle.NONE)
Then, when you persist ArchiveTrafficMeasure, you should set PK as ArchiveTrafficMeasureId and persist it.
I am running into an issue.
I search for several hours but did not find any anwers.
What I want to do is a sql select, in which the ORDER clause depends on the value of a column (so it changes for every tuples).
I managed to do it via HQL with something like that :
SELECT NEW myDTO(m.id, m.name, " + calculDistance + " AS distance) FROM Table m GROUP BY m.mercId ORDER BY distance ASC
With calculDistance depending of m.latitude and m.longitude
This works fine.
However, my request is much more complicated than that and for reading, update and such reasons, I'd like to do it directly with JPA.
Do you know if this is possible?
Thanks for your help.
EDIT
Here is the part of my table structure (I put only the needed columns):
#Entity
#Table(name = "td_merchant")
#XmlRootElement
#SequenceGenerator(name = "td_merchant_id_seq", sequenceName = "td_merchant_id_seq")
public class Merchant implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(generator = "td_merchant_id_seq", strategy = GenerationType.SEQUENCE)
#Column(name = "merc_id")
private Integer mercId;
#Column(name = "merc_name")
private String mercName;
#Column(name = "merc_latitude")
private Double mercLatitude;
#Column(name = "merc_longitude")
private Double mercLongitude;
...
}
I also faced same issue, i wrote one function which was taking input for order by as well as asc and desc seq.
public List<CompanyName> loadAllCompanies(CompanySortField sortField, boolean ascending) {
String queryString = "select new com.Company(u.name, u.surname, " +
" country.name, country.population, " +
" city.name) from Company u left join u.city as city left join u.country as country " +
" order by " + sortField.getField() + (ascending ? " asc " : " desc ");
return entityManager.createQuery(queryString).getResultList();
}
You can try in this way, only thing is you need to fire another query to find out company sort field.