Custom name for JPA #JoinColumn - spring

A FailedDeliveryOrder class has a field with the type of DeliveryOrder class, while the DeliveryOrder class has a field with the type of List of ProductDes class. The DeliveryOrder field will be embedded in the same table as FailedDeliveryOrder.
How can I specify a custom name for the table of the List of ProductDes ?
FailedDeliveryOrder.java
#Table(name = "FailedDeliveryOrder")
#Entity
public class FailedDeliveryOrder {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Embedded
private DeliveryOrder deliveryOrder;
public FailedDeliveryOrder() {
}
public FailedDeliveryOrder(DeliveryOrder deliveryOrder) {
this.deliveryOrder = deliveryOrder;
}
//setter and getter
}
DeliveryOrder.java
public class DeliveryOrder {
#Entity
public static class ProductDes {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
public Product() {}
// setter and getter
}
#OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.ALL})
#JoinColumn(
name = "DeliveryOrder_ID",
nullable = false
)
#OrderColumn(
name = "ProductDes_Position",
nullable = false
)
private List<ProductDes> product_descriptions = new ArrayList<Product>();
public DeliveryOrder() {
}
public DeliveryOrder(List<ProductDes> products) {
this.setProduct_descriptions(products);
}
public List<ProductDes> getProduct_descriptions() {
return product_descriptions;
}
public void setProduct_descriptions(List<ProductDes> product_descriptions) {
this.product_descriptions = product_descriptions;
}
}
Instead of autogenerated name.

Related

Spring JPA - How can I make JpaRepository queries using an #Embedded property?

I'm trying to make a existsBy query using a property that comes from an embedded class, but I'm receiving "No property 'cpf' found for type 'Patient'".
The class Patient uses the Person class as embedded.
Person.java
#Embeddable
#Data
public class Person {
#Column(nullable = false, length = 11)
private String cpf;
#Column(name = "full_name", nullable = false, length = 60)
private String fullName;
#Column(nullable = false)
private String birthdate;
#Column(name = "email", nullable = true, length = 30)
private String emailAddress;
#Column(name = "cellphone_number", nullable = true, length = 11)
private String cellphoneNumber;
}
Patient.java
#Data
#Entity
#Table(name = "tb_patient")
public class Patient implements Serializable {
#Serial
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "patient_id")
private UUID id;
#Column
private LocalDateTime registrationDate;
#Embedded
private Person Person;
}
PatientController.java (part of)
#PostMapping
public ResponseEntity<Object> savePatient(#RequestBody Person person) {
if(patientService.existsByCpf(person.getCpf())) {
return ResponseEntity.status(HttpStatus.CONFLICT).body("CONFLICT: CPF number is already in use!");
}
var patientModel = new Patient();
BeanUtils.copyProperties(person, patientModel);
patientModel.setRegistrationDate(LocalDateTime.now(ZoneId.of("UTC")));
return ResponseEntity.status(HttpStatus.CREATED).body(patientService.save(patientModel));
}
PatientService.java (part of)
#Service
public class PatientService {
final PatientRepository patientRepository;
public PatientService(PatientRepository patientRepository) {
this.patientRepository = patientRepository;
}
public boolean existsByCpf(String cpf) {
return patientRepository.existsByCpf((cpf));
}
PatientRepository.java
#Repository
public interface PatientRepository extends JpaRepository<Patient, UUID> {
boolean existsByCpf(String cpf);
}
How can I pass the #Embedded properties to the #Repository?
You can try separate by _ embedded filed name and it's filed.
#Repository
public interface PatientRepository extends JpaRepository<Patient, UUID> {
boolean existsByPerson_Cpf(String cpf);
}

JPA lazy initialization error with #OneToMany #EmbeddedId

In Sprinboot/JPA I defined an entity with one-to-may association as follows:
#Entity
#Table(name = "useraccount", catalog = "useraccount")
public class UserAccount implements Serializable
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
//other stuff...
#OneToMany(mappedBy ="tokenId.user", cascade = {CascadeType.REMOVE, CascadeType.MERGE, CascadeType.REFRESH}, orphanRemoval =true, fetch=FetchType.LAZY)
private Set<SecureToken> tokens = new HashSet<>();
public Set<SecureToken> getTokens()
{
return this.tokens;
}
//other getter and setter
}
The SecureToken entity:
#Entity
#Table(name = "secureToken", catalog = "useraccount")
public class SecureToken implements Serializable
{
#EmbeddedId
public SecureTokenId tokenId= new SecureTokenId();
#Column(unique = true)
private String token;
private Timestamp isConsumed;
#CreationTimestamp
#Column(updatable = false)
private Timestamp timestamp;
#Column(updatable = false)
#Basic(optional = false)
private Timestamp expireAt;
#MapsId("user_id")
#JoinColumn(name = "user_id", referencedColumnName ="id")
#ManyToOne
private UserAccount user;
public SecureToken(UserAccount user, String token, String tokenType, Timestamp timestamp, Timestamp expire)
{
super();
this.token=token;
this.tokenId.setTokenType(tokenType);
this.tokenId.setUser(user);
this.timestamp=timestamp;
this.expireAt=expire;
this.isExpired=false;
}
}
The SecureTokenId:
#Embeddable
public class SecureTokenId implements Serializable
{
#Column(name="tokenType")
private String tokenType;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id")
private UserAccount user;
public SecureTokenId()
{
super();
}
public SecureTokenId(String tokenType)
{
//this.user_id=user_id;
this.tokenType=tokenType;
}
#Override
public boolean equals(Object o)
{
if (o == null || getClass() != o.getClass())
return false;
SecureTokenId that = (SecureTokenId) o;
return Objects.equals(this.tokenType, that.tokenType) &&
Objects.equals(this.user.getId(), that.user.getId());
}
#Override
public int hashCode() {
return Objects.hash(tokenType, this.user.getId());
}
public void setTokenType(String tokenType)
{
this.tokenType=tokenType;
}
public String getTokenType()
{
return this.tokenType;
}
public void setUser(UserAccount user)
{
this.user=user;
}
public UserAccount getUser()
{
return this.user;
}
public Long getTokenId()
{
return this.user.getId();
}
}
But calling the method getToken() of entity UserAccount gets the famous "LazyInitializationException". I generally use Hibernate.initialize, but with this configuration I cannot get rid of the problem.
This how I create a token within a #Service annoted SecureTokenService class.
#Override
#Transactional
public SecureToken generateToken(UserAccount user, String tokenType)
{
byte[] random = new byte[64];
new SecureRandom().nextBytes(random);
Timestamp timestamp = java.sql.Timestamp.valueOf(LocalDateTime.now());
LocalDateTime expire= LocalDateTime.now().plusHours(12);
SecureToken token = new SecureToken(new SecureTokenId(user, tokenType),Base64.encodeBase64URLSafeString(random),
timestamp, Timestamp.valueOf(expire));
return token;
}
Then in the UserService class (#Service annotated) I try to create a token:
SecureToken token = secureTokenService.generateToken(user, type);
secureTokenService.save(token);
user.addSecureToken(token); //Error
this.save(user)
When I try to associate the token with the user the error is thrown. Without that statement, the application seems working but even with "spring.jpa.open-in-view = false" in application.properties calling user.getTokens() rises the lazy initialization error.
In parent child relationship, you didn't declare any parent reference from child side.
In the parent side (UserAccount), you declared as follows
#OneToMany(mappedBy ="user"....
Which means your child side (SecureToken) there is no such property named user.
To get rid of this situation,
First you need to declare user inside of SecureToken / SecureTokenId. From your definition, you declared user_id inside SecureTokenId, instead declare user inside SecureTokenId.
...
public class SecureTokenId ... {
...
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id")
private UserAccount user;
...
}
Then in the UserAccount declare the #OneToMany as follows
#OneToMany(mappedBy ="tokenId.user"...
private Set<SecureToken> tokens;

AuditingEntityListener is not working for the entity that extends another abstract entity in spring jpa

I have used the #CreatedBy, #CreatedDate, #LastModifiedBy, and #LastModifiedDate annotation on their respective fields. By using #MappedSuperclass,#EntityListeners i able to persist above columns.
But this is not working for the below case:
#MappedSuperclass
#EntityListeners(AuditingEntityListener.class)
public abstract class Auditable<U> {
#CreatedBy
protected U createdBy;
#CreatedDate
#Temporal(TIMESTAMP)
protected Date creationDate;
#LastModifiedBy
protected U lastModifiedBy;
#LastModifiedDate
#Temporal(TIMESTAMP)
protected Date lastModifiedDate;
}
#Entity
#Table(name = "tabel1")
#PrimaryKeyJoinColumn(name = "ID")
class A extends B {
#Column(name = "NAME1", nullable = false)
private String name1;
#Column(name = "CONTENT1", nullable = false)
private String content1;
}
#Entity
#Table(name = "tabel2")
public abstract class B extends Auditable{
#Id
#GeneratedValue
#Column(name = "ID", nullable = false)
private int id;
#Column(name = "NAME", nullable = false)
private String name;
#Column(name = "CONTENT", nullable = false)
private String content;
}
AuditorAwareImpl.java
public class AuditorAwareImpl implements AuditorAware<String>
{
#Override
public Optional<String> getCurrentAuditor()
{
return Optional.ofNullable("Saravanan");
}
}
JpaAuditConfiguration.java
#Configuration
#EnableJpaAuditing(auditorAwareRef = "auditorProvider")
public class JpaAuditConfiguration
{
#Bean
public AuditorAware<String> auditorProvider()
{
return new AuditorAwareImpl();
}
}
In the case, Entity B is populated with audit columns. But Entity A is not. Is there a way to populate Entity A or did i missed anything here..??
I added #Entity annotation to your classes:
#Entity
public class A extends B {
#Id
#GeneratedValue
private Integer id;
private String name;
private String content;
}
#Entity
public class B extends Auditable<String> {
#Id
#GeneratedValue
private Integer id;
private String name;
private String content;
}
Persistence config class (for Spring Boot):
#Configuration
#EnableJpaAuditing
public class PersistenceConfig {
}
Everything works perfectly!

Hibernate: org.hibernate.MappingException: Could not determine type for: java.util.Set

I am trying to use Set in hibernate. The problem I don't know to how to write annotation on the Set table.
#Entity
#Table(name="user_settings")
public class UserSettings {
#Id
#GeneratedValue
private int id;
private int userid;
protected Set<Integer>foreignLanguageId;
public UserSettings() {
}
public UserSettings(int userid, int nativeLanguageId,
Set<Integer> foreignLanguageId, Date birthday) {
this.userid = userid;
this.nativeLanguageId = nativeLanguageId;
this.foreignLanguageId = foreignLanguageId;
this.birthday = birthday;
}
#OneToMany
#JoinColumn(name="userid", nullable=false)// This annotation
public Set<Integer> getForeignLanguageId() {
return foreignLanguageId;
}
Error:
org.hibernate.MappingException: Could not determine type for: java.util.Set, at table: user_settings, for columns: [org.hibernate.mapping.Column(foreignLanguageId)]
at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:314)...........
You should to use entity to make an association not id
#Entity
#Table(name="user_settings")
public class UserSettings {
private Set<Language> foreignLanguages;
#OneToMany
#JoinColumn(name="fk_user_setting", nullable = false)
public Set<Language> getForeignLanguages() {
return foreignLanguages;
}
}
if you want to use Integer you can use #ElementCollection
#Entity
#Table(name="user_settings")
public class UserSettings {
private Set<Integer> foreignLanguages;
#ElementCollection
public Set<Integer> getForeignLanguages() {
return foreignLanguages;
}
}

Sequence in inheritance with hibernate annotation and oracle

I have an inheritance
Abstract class A:
#MappedSuperclass
public abstract class A {
public Integer id;
#Id
#Column(name = "ID", nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
}
Subclass B, that uses a sequence:
#Entity
#Table(name = "B")
public class B
extends A {
private String descripction;
#Override
#SequenceGenerator(name = "SEQ_TRANSACTIONID", sequenceName = "SEQ_TRANSACTION", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_TRANSACTIONID")
public Integer getId() {
return id;
}
#Column(name = "DESCRIPTION", nullable = false)
public String getDescripction() {
return descripction;
}
public void setDescripction(String descripction) {
this.descripction = descripction;
}
}
And subclass C, that does not need a sequence:
public class C extends A {
}
The class B needs to generate a sequence but the class C doesn't.
I run the proyect with "hibernate.hbm2ddl.auto" in "create-drop". But SEQ_TRANSACTIONID is never created.
I've built this test so you can reproduce the error.
Help me please.....
Thanks in advance.

Resources