Any thoughts if there's a way to have a custom method for handling null or any other exceptions happening during projection creation?
In the below JPQL query I'm trying to compose a custom object, but when there's no data under column updatedBy (it's null in database) - then it fails internally since cannot proceed with null object any further (getUpdatedBy -> getProfile -> getName).
#Query("select new john.home.com.demo.repository.projections.AgreementType(agreement.name, " +
"agreement.type, " +
"agreement.audit.createdBy.profile.name, " +
"agreement.audit.updateDate, " +
"agreement.audit.updatedBy.profile.name) from Agreement agreement")
List<AgreementType> findAgreementTypes();
Here are my entities:
Agreement:
#Setter
#Getter
#NoArgsConstructor
#Entity
#Table(name = "AGREEMENT")
public class Agreement {
#Id
#Column(name = "AGREEMENT_ID")
private Long id;
#Column(name = "NAME")
private String name;
#Column(name = "TYPE")
private String type;
#Embedded
Audit audit;
Embeddable Audit
#Getter
#Setter
#Embeddable
public class Audit {
#OneToOne
#JoinColumn(name = "CREATED_BY")
private SystemProcess createdBy;
#Column(name = "CREATION_DATE")
private LocalDate creationDate;
#Column(name = "UPDATE_DATE")
private LocalDate updateDate;
#OneToOne
#JoinColumn(name = "UPDATED_BY")
private SystemProcess updatedBy;
SystemProcess:
#Getter
#Setter
#Entity
#Table(name = "sys_process")
public class SystemProcess {
#Id
#Column(name = "PROCESS_ID")
private Integer id;
#Column(name = "PROCESS_MSG_TXT")
private String messageText;
#OneToOne
#JoinColumn(name = "PROFILE_ID")
private SystemProfile profile;
SystemProfile:
#Getter
#Setter
#Entity
#Table(name = "sys_profile")
public class SystemProfile {
#Id
#Column(name = "PROFILE_ID")
private Integer id;
#Column(name = "PROFILE_NM")
private String name;
}
Here's the JPQL query I've used, however it doesn't work due to unknown reason
#Query("select new dan.home.pl.demo.repository.projections.AgreementType(" +
"agreement.name, " +
"agreement.audit.createdBy.profile.name, " +
"case when (agreement.audit.updatedBy is null) then 'Dummy Name' else agreement.audit.updatedBy.profile.name end" +
") from Agreement agreement")
List<AgreementType> findAgreementTypes();
You can use the case statement to achieve this
Check the documentation here
https://docs.jboss.org/hibernate/orm/4.3/devguide/en-US/html/ch11.html
Something like
case when agreement.audit is not null then agreement.audit.updatedBy.profile.name end
Related
I have entity
#Data
#Entity
#Table(name = "event")
#DynamicInsert
#AllArgsConstructor
#NoArgsConstructor
#EqualsAndHashCode
public class Event {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "accountable_unit_id")
private Long accountableUnitId;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "type_id")
private EventType type;
#Column(name = "name")
private String name;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "status_id")
#Enumerated(EnumType.STRING)
private EventStatus status;
#Column(name = "user_info")
private String userInfo;
#Column(name = "deadline_dttm")
private Instant deadlineOn;
#Column(name = "completed_dttm")
private Instant completedOn;
#Column(name = "status_modify_dttm")
private Instant statusUpdatedOn;
#Column(name = "create_dttm")
private Instant createdOn;
#Column(name = "modify_dttm")
private Instant updatedOn;
#Version
#Column(name = "version")
private int version;
#Column(name = "status_name")
private String statusName;
And I have repository with one method
#Repository
public interface EventRepository extends JpaRepository<Event, Long>, JpaSpecificationExecutor<Event> {
#Query(value = "select e.*,\n" +
" CASE \n" +
" WHEN es.code = 'in_progress' and e.deadline_dttm < now()\n" +
" THEN 'Просрочено' \n" +
" ELSE es.\"name\"\n" +
" END status_name \n" +
"from public.\"event\" e join public.event_status es on e.status_id = es.id",
countQuery = "select count(*) from public.\"event\"",
nativeQuery = true)
Page<Event> findAllWithDynamicStatusName(Specification<Event> spec, Pageable pageable);
}
But unfortunately Specification doesn't work with native query.
Does anyone know how to rewrite this SQL to JPQL or HQL? The main problem is I can't use SQL CASE structure like I am using it in the native query.
Or maybe you can give me an advise on how to make it works with Specification and native queries?
Thank you very much for your answers!
Below query might help you
select
CASE (es.code = 'in_progress' and
es.deadline_ddtm = now()) THEN 'Просрочено'
ELSE es.name END status_name
from public.event e join public.event_status es on
e.status_id=es.id
I hope this helps!
I have a table that holds events where the data is stored as a JSON object.
What i'am trying to do is have different entities mapped to the same table, because some of these events need to join with other tables to be useful.
What i tried doing:
EntityA is the "default" entity for the table, all events are received in this entity an them stored.
#Entity(name = "entity_a")
#Table(name = "table_a")
public class EntityA {
#Id
private UUID id;
#Column(name = "fielda")
private String fieldA;
#Column(name = "fieldb")
private Integer fieldB;
#Column(name = "json_field")
private Object jsonField;
}
EntityAB is a map of the same table with a new field that is a join with another table.
#Entity(name = "entity_ab")
#Table(name = "table_a")
public class EntityAB {
#Id
private UUID id;
#Column(name = "fielda")
private String fieldA;
#Column(name = "fieldb")
private Integer fieldB;
#Column(name = "json_field")
private Object jsonField;
#ManyToOne
#ManyToOne
#JoinColumnsOrFormulas(value = {
#JoinColumnOrFormula(formula = #JoinFormula(value = "JSON_VALUE(jsonField, '$.field_id_a')", referencedColumnName = "field_id_a")),
#JoinColumnOrFormula(formula = #JoinFormula(value = "JSON_VALUE(jsonField, '$.field_id_b')", referencedColumnName = "field_id_b")),
#JoinColumnOrFormula(formula = #JoinFormula(value = "JSON_VALUE(jsonField, '$.fieldc')", referencedColumnName = "fieldc")),
})
private EntityB entityB;
}
EntityB is used in the EntityAB.
public class EntityB implements Serializable {
#EmbeddedId
private EntityBId id;
#Column(name = "fieldc")
private String fieldC;
}
#Embeddable
public class EntityBId implements Serializable {
#Column(name = "field_id_a")
private String fieldIdA;
#Column(name = "field_id_b")
private Integer fieldIdB;
#Column(name = "field_id_c")
private Integer fieldIdC;
}
When starting the application, it gives me this error:
referencedColumnNames(field_id_a, field_id_b, fieldc) of EntityAB.entityB referencing EntityB not mapped to a single property
If i dont use the fields "field_id_a" and "field_id_b" (EmbeddedId) in the join, it works, but it's not the right join. From what i have searched it looks like i can't have a parcial PK join when using "EmbeddedId", is that correct?
I have a problem. Please help me.
Partner.java
#Entity
#Table(name = "partners")
#Data
public class Partner {
public Partner() {
this.status = UserStatus.NOT_YET_ACTIVED;
this.createdDate = LocalDateTime.now();
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull
private String name;
private String surname;
#NotNull
#Column(unique = true)
private String email;
#NotNull
private String phone;
#Column(columnDefinition="ENUM('MALE', 'FEMALE', 'COMPANY')")
#Enumerated(EnumType.STRING)
private Gender gender;
#Column(name = "country_id")
private Integer countryId;
#Column(name = "city_id")
private Integer cityId;
#Column(name = "street_id")
private Integer streetId;
#Column(columnDefinition="ENUM('ACTIVE', 'NOT_YET_ACTIVED', 'BLOCKED', 'DELETED')")
#Enumerated(EnumType.STRING)
private UserStatus status;
#NotNull
#Column(name = "is_company")
private Integer isCompany;
#Column(name = "created_date")
private LocalDateTime createdDate;
#OneToOne(mappedBy = "partner", cascade=CascadeType.ALL)
private VerificationToken verificationToken;
}
VerificationToken.java
#Entity
#Table(name = "user-token")
#NoArgsConstructor
public class VerificationToken {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Getter
private Long id;
#Getter
private String token;
#OneToOne(targetEntity = Partner.class, fetch = FetchType.EAGER)
#JoinColumn(nullable = false, name = "partner_id", foreignKey = #ForeignKey(name = "FK_VERIFY_USER"))
#Getter
private Partner partner;
#Column(name = "created_date")
#Getter
private LocalDateTime createdDate;
public VerificationToken(final Partner partner) {
this.createdDate = LocalDateTime.now();
this.token = UUID.randomUUID().toString();
this.partner = partner;
}
}
#Override
public PartnerResponseDto save(PartnerRequestDto partnerRequestDto) {
var a = partnerMapper.partnerRequestDtoTOPartner(partnerRequestDto);
VerificationToken v = new VerificationToken(a);
a.setVerificationToken(v);
var partner = ipartnerRepository.save(a);
if (partner == null)
throw new RuntimeException();
return partnerMapper.partnerToPartnerResponseDto(partner);
}
i want to do when partner save succesfuly, then save the verification token and partner id to user-token table.
when i save partner request hibernate response me the following exception
java.sql.SQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (ft_partner_and_client_ms.partners, CONSTRAINT FK_VERIFY_USER FOREIGN KEY (id) REFERENCES user-token (id))
I don't understand why I'm getting this error. Please help
I have two entites as follows
user entity
#Entity
#Table(name = "user")
#Getter
#Setter
public class UserEntity{
#Id
#GeneratedValue(strategy = GeneratedType.IDENTITY)
#Column(name = "user_id")
private Long userId;
#Column(name = "user_name")
private String name;
#OneToOne(Cascade=CascadeType.ALL, mappedBy="user")
private UserAddressEntity addressEntity;
}
user address entity
#Entity
#Table(name = "user_address")
#Getter
#Setter
public class UserAddressEntity{
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "user_id")
private Long userId;
#Column(name = "address")
private String address;
#OneToOne
#JoinColumn(name = "user_id", nullable = false, referencedColumnName = "user_id")
private UserEntity user;
}
I am saving user entity as follows in service class
#Service
public class UserService{
#Autowired
private UserRepository userRepository;
public void saveUser(){
UserEntity userEntity=new UserEntity();
UserAddressEntity userAddressEntity=new UserAddressEntity();
//logic here
userEntity.setAddressEntity(userAddressEntity);
userRepository.save(userEntity);
}
}
After saving entity user_id column is not being saved in user_address table. It's value is saved as null.I can't seem to find where the issue is.
EDIT:
I have added following to entities after answer referred in comments but I am getting this error
Infinite recursion (StackOverflowError)
#Entity
#Table(name = "user")
#Getter
#Setter
public class UserEntity{
#Id
#GeneratedValue(strategy = GeneratedType.IDENTITY)
#Column(name = "user_id")
private Long userId;
#Column(name = "user_name")
private String name;
#OneToOne(Cascade=CascadeType.ALL, mappedBy="user")
private UserAddressEntity addressEntity;
//added this
public void setAddressEntity(UserAddressEntity addressEntity){
if (!addressEntity.equals(this.addressEntity)){
this.addressEntity=addressEntity;
addressEntity.setUser(this);
}
}
#Entity
#Table(name = "user_address")
#Getter
#Setter
public class UserAddressEntity{
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "user_id")
private Long userId;
#Column(name = "address")
private String address;
#OneToOne
#JoinColumn(name = "user_id", nullable = false, referencedColumnName = "user_id")
private UserEntity user;
//added this
public void setUser(UserEntity user){
if (!user.equals(this.user){
this.user=user;
}
}
}
You need to set the relationship correctly in UserService.saveUser():
userEntity.setAddressEntity(userAddressEntity);
userAddressEntity.setUser(userEntity);
Also, use regular getters/setters, no need to add logic there.
The recommended/best way to map a #OneToOne is to use #MapsId. With that approach, you don’t need at all a bidirectional association.
I would advise you to take look at link below, there you have answer to your question with example how to save and map between objects.
https://vladmihalcea.com/the-best-way-to-map-a-onetoone-relationship-with-jpa-and-hibernate/
I am trying to map a bidirectional One-to-Many relationship in Hibernate. In the build logs I receive the error "repeated column in mapping for entity."
What is generating the error?
The entity source code is below. One has a compound primary key. I am using Lombok to generate getters and setters.
The relationship: Award (One) --> AwardReceived (Many)
Award Entity
#Entity
#Table(name = "awards")
#JsonInclude(JsonInclude.Include.NON_NULL)
#Data
public class Award implements Serializable {
#Id
#Column(name = "award_id")
private Long awardId;
#OneToMany(cascade=CascadeType.ALL, mappedBy = "award")
private Set<AwardReceived> awardsReceived;
#Column(name = "award_type")
private String awardType;
#Column(name = "award")
private String award;
#Column(name = "description")
private String description;
}
AwardReceived Entity
#Entity
#Table(name = "awards_received")
#JsonInclude(JsonInclude.Include.NON_NULL)
#Data
public class AwardReceived implements Serializable{
#EmbeddedId
#JsonUnwrapped
private AwardReceivedPk awardReceivedPk;
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "award_id")
private Award award;
#Column(name = "award_name")
private String awardName;
#Column(name = "citation")
private String citation;
}
AwardReceivedPk
#Embeddable
#JsonInclude(JsonInclude.Include.NON_NULL)
#Data
public class AwardReceivedPk implements Serializable{
#JsonIgnore
#Column(name = "client_no")
private String clientNo;
#Column(name = "award_id")
private Long awardId;
#Column(name = "year")
private Long year;
}
Please try
#ManyToOne(cascade=CascadeType.ALL)
private Award award;
instead of
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "award_id")
private Award award;