#Transient can't get data from Entity - java

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?

Related

Correct use of #Transient

I have a entity, something like this:
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Entity(name = "warranties")
public class Warranty implements Comparable<Warranty> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "warranty_pk")
private Long id;
#Column(nullable = false)
private Date startDate;
#Column(nullable = false)
private Date expireDate;
#Column
private String note;
#Transient
private Date displayDate;
}
}
Notice that displayDate is annotated with #Transient.
I have two functionalities related to this entity, one is to fetch some of them, to do that I need to check expiration dates. So in my repository I have the following query:
#Query(value =
"SELECT "
+ "IF(expire_date < ((CURDATE() + INTERVAL 1 DAY) - INTERVAL 1 SECOND), expire_date, (expire_date - INTERVAL 90 day)) AS display_date, * "
+ "FROM warranties "
+ "WHERE expire_date < ((CURDATE() + INTERVAL 1 DAY) - INTERVAL 1 SECOND) + INTERVAL 90 DAY "
+ "AND expire_date <= :expire_date "
+ "AND start_date >= :startDate "
+ "AND expire_date <= :endDate + INTERVAL 90 DAY "
+ "ORDER BY display_date DESC",
nativeQuery = true)
List<Warranty> findWarranties(#Param("expire_date") Date expireDate,
#Param("startDate") Date startDate, #Param("endDate") Date endDate);
Its that way so I can retrieve the "displayDate" calculated by the database.
It works fine when I use the following import:
import org.springframework.data.annotation.Transient;
And the other functionality is a save, where I save a given note.
For that case I get the following error:
Caused by: java.sql.SQLSyntaxErrorException: Unknown column 'warranty0_.display_date' in 'field list'
If I use the following import, the second functionality works fine:
import javax.persistence.Transient;
But then the findWarranties doesn't return displayDate.
Any thoughts?

JPA, postgres: can't convert data to class

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.

How to generate entity class without create table automatic

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.

HQL Query with LEFT JOIN and WHERE not giving results

Working with HQL, on this simplified scenario:
String query = "SELECT new CustomUser(" +
"user.userID AS id," +
"user.username AS username)" +
"FROM User AS user" +
" LEFT JOIN user.friends as friend " +
" where user.username like (:query)" +
" OR " +
" friend.username like (:query) ";
This is giving back only those Users that have at least one friend, but I want to get Users by a condition, beyond of having Friends or not.
Dynamic instantiation is used because of domain requirements
I've noticed that it gives all Users, having Friends or not, if there is no condition on the joined table (friend.username like (:query))
These are my tables:
User
#Id...
protected Integer userID;
#Column(name = "username")
private String username;
#OneToMany(mappedBy = "user", cascade = CascadeType.REMOVE)
private List<Friend> friends;
Friend
#Id
private Integer friendID;
#Column(name = "username")
private String username;
#ManyToOne(cascade = CascadeType.DETACH)
#JoinColumn(name="userid")
private User user;
Note: it works as I expect on native SQL
You can try this query.
String query = "SELECT new CustomUser(" +
"user.userID AS id," +
"user.username AS username)" +
"FROM User AS user" +
" LEFT OUTER JOIN user.friends as friend " +
" where user.username like (:query)" +
" OR " +
" friend.username like (:query) ";

JPA Hibernate. Select : ORDER clause depending on the value of a column

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.

Categories

Resources