I have a question:
Here is my entity:
public class CompanyBindingEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "BINDING_ID", nullable = false)
private int companyBindingId;
#NotNull
#Embedded
#Valid
private CompanyEntity company;
....
}
Here is CompanyEntity:
#NoArgsConstructor
#AllArgsConstructor
#Embeddable
#Builder
#Data
public class CompanyEntity {
#Id
#NotNull
#Column(name = "COMPANY_ID")
private Integer companyId;
#NotNull
#Column(name = "COMPANY_NAME")
private String companyName;
}
And I want to implement
findByCompanyId(int companyId)
method in my service and repository. But I am receiving this error:
Could not locate field name [companyId] on class [...Entity]
because the companyId is inside CompanyEntity, not in CompanyBindingEntity. I need to find a way about how to solve this. Am I missing a special annotation to search for a nested element?
Thanks a lot for reading!
First, you need to define an association between CompanyBindingEntity and CompanyEntity, for example:
#NotNull
#Embedded
#Valid
#OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, fetchType = FetchType.EAGER)
#JoinColumn(name = "COMPANY_ID")
private CompanyEntity company;
Then in the table that holds CompanyBindingEntity define a foreign key to bind "COMPANY_ID" to the ID for CompanyEntity.
Related
I'm newbie in Spring boot and making first time an experimental app. This app consist on 3 classes / tables:
Account:
has an account numbers that can be call by JournalEntryDetail, so I get #onetoone relation
JournalEntryMaster:
can have many JournalEntryDetail
I use here #OnetoMany annotation
JournalEntryDetail:
can have one JournalEntryMaster
Foreign key to Account, as Account number should be equal b/w JournalEntDetail & Account table
I get an error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name
'entityManagerFactory' defined in class path resource
[org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation
of init method failed; nested exception is org.hibernate.AnnotationException: #Column(s) not
allowed on a #OneToOne property: com.accounts.entity.JournalEntryMaster.jvNumber
I can understand what does error means but unfortunately I did not find solution, so I came here. Any one could advise will be appreciated.
I copy entities hereunder:
accountnumber
public class Account {
#Id
#GeneratedValue
#Column(name="account_id")
private Long id;
#Column(name="account_number")
private Long accountNumber;
#Column(name="account_name")
private String accountName;
#Enumerated(EnumType.STRING)
#Column(name="dr_or_credit")
private DrOrCrSide drOrCrSide;
#Enumerated(EnumType.STRING)
#Column(name="account_type")
private AccountType accountType;
#ManyToOne(cascade = CascadeType.ALL)
private JournalEntryDetail journalEntryDetail;
JournalEntryMaster
#Entity
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#EqualsAndHashCode
#ToString
public class JournalEntryMaster {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id")
private Long id;
#OneToOne
#Column(name="jv_number")
private Long jvNumber;
#Column(name="jv_master_date")
private Date Date;
#Column(name="jv_reference_no")
private String ReferenceNo;
#Column(name="memo")
private String Memo;
#Column(name="posted")
private boolean Posted;
#OneToMany(targetEntity = JournalEntryDetail.class, cascade = CascadeType.ALL)
private Set<JournalEntryDetail> journalEntryDetail = new HashSet<>();
}
JourEntryDetail
#Entity
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#EqualsAndHashCode
#ToString
public class JournalEntryDetail {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name="account_number")
private Long accountNumber;
#Enumerated(EnumType.STRING)
#Column(name="jv_detail_drcr")
private DrOrCrSide DrCr;
#Column(name="amount")
private Double Amount;
#Column(name="memo")
private String Memo;
#ManyToOne
#JoinColumn(name = "jv", referencedColumnName = "id")
private JournalEntryMaster jv;
#JoinColumn(name = "account_fk_jv", referencedColumnName = "account_number")
#OneToOne(targetEntity = Account.class, cascade = CascadeType.ALL)
private Account account_number;
#JoinColumn(name = "jvnumber_fk", referencedColumnName = "jv_number")
#OneToOne(targetEntity = JournalEntryMaster.class, cascade = CascadeType.ALL)
private JournalEntryMaster jvNumber;
In
public class JournalEntryMaster {
...
#OneToOne <-- remove this annotation
#Column(name="jv_number")
private Long jvNumber;
You use Long for the jvNumber. If this is just a database column and its not related to an entity, don't use #OneToOne. You can remove the annotation and your error #Column(s) not allowed on a #OneToOne property: com.accounts.entity.JournalEntryMaster.jvNumber will disappear.
On the other hand, if it is related to an entity, you have to use JoinColumn instead of Column and use your EntityClass instead of Long.
Remove #OneToOne from JournalEntryMaster above #Column(name="jv_number") private Long jvNumber and relation of JournalEntryDetail with JournalEntryMaster
is #ManyToOne not #OneToOne. you give two relation together for one table in JournalEntryDetail
remove:
#JoinColumn(name = "jvnumber_fk", referencedColumnName = "jv_number")
#OneToOne(targetEntity = JournalEntryMaster.class, cascade = CascadeType.ALL)
private JournalEntryMaster jvNumber;
Here down modified code:
JournalEntryMaster
#Entity
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#EqualsAndHashCode
#ToString
public class JournalEntryMaster {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id")
private Long id;
#Column(name="jv_number")
private Long jvNumber;
#Column(name="jv_master_date")
private Date Date;
#Column(name="jv_reference_no")
private String ReferenceNo;
#Column(name="memo")
private String Memo;
#Column(name="posted")
private boolean Posted;
#OneToMany(targetEntity = JournalEntryDetail.class, cascade = CascadeType.ALL)
private Set<JournalEntryDetail> journalEntryDetail = new HashSet<>();
}
JourEntryDetail
#Entity
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#EqualsAndHashCode
#ToString
public class JournalEntryDetail {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name="account_number")
private Long accountNumber;
#Enumerated(EnumType.STRING)
#Column(name="jv_detail_drcr")
private DrOrCrSide DrCr;
#Column(name="amount")
private Double Amount;
#Column(name="memo")
private String Memo;
#ManyToOne
#JoinColumn(name = "jv", referencedColumnName = "id")
private JournalEntryMaster jv;
#JoinColumn(name = "account_fk_jv", referencedColumnName = "account_number")
#OneToOne(targetEntity = Account.class, cascade = CascadeType.ALL)
private Account account_number;
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 have a file named data.sql which contains SQL queries 'INSERT INTO'.
I have table User which model is:
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
// other fields
#OneToMany(cascade = CascadeType.ALL,
fetch = FetchType.LAZY,
mappedBy = "user")
#Column(name = "vacations")
private Set<Vacation> vacations = new HashSet<>();
And I have model Vacation where is:
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#NotNull
#Column(name = "begin_date")
private LocalDateTime beginDateOfVacation;
#NotNull
#Column(name = "end_date")
private LocalDateTime endDateOfVacation;
#NotEmpty
#Column(name = "type")
private String typeOfVacation;
#NotEmpty
#Column(name = "reason")
private String reasonOfVacation;
#ManyToOne(cascade = {CascadeType.ALL}, fetch = FetchType.LAZY)
#JoinColumn(name = "user_id", nullable = false)
private User user;
And in my data.sql I am trying to insert into vacation User with existing ID.
It "passing" threw compiler, but on localhost I can see only this:
Could not write JSON: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: com.springproject27.springproject.user.User["vacations"])
It is H2 Database Engine, the query which I try to pass is:
INSERT INTO VACATION(ID,BEGIN_DATE,END_DATE,TYPE,REASON,USER_ID) VALUES
(22,'2012-09-17 18:47:52.69','2012-09-20 18:47:52.69','Unpaid leave','Sick',10);
As you see its happening because of JSON recursion when you are trying to serialize your data because of bi-directional relationship between User entity & Vacation entity. Preferred method to use #JsonIgnoreProperties (if you are using Jackson 2.0+ version) to break the recursion during serialization.
NOTE: Other way to break the JSON recursion is using JsonBackReference and JsonManagedReference in combiation. But I prefer #JsonIgnoreProperties due to no data loss during serialization.
If you are using Lombok, only use #Getter & #Setter annotation not #ToString (or #Data which has #ToString included), as it will cause the same recursion issue.
class User{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
// other fields
#OneToMany(cascade = CascadeType.ALL,
fetch = FetchType.LAZY,
mappedBy = "user")
#Column(name = "vacations")
#JsonIgnoreProperties("user")
private Set<Vacation> vacations = new HashSet<>();
}
class Vacation{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#NotNull
#Column(name = "begin_date")
private LocalDateTime beginDateOfVacation;
#NotNull
#Column(name = "end_date")
private LocalDateTime endDateOfVacation;
#NotEmpty
#Column(name = "type")
private String typeOfVacation;
#NotEmpty
#Column(name = "reason")
private String reasonOfVacation;
#ManyToOne(cascade = {CascadeType.ALL}, fetch = FetchType.LAZY)
#JoinColumn(name = "user_id", nullable = false)
#JsonIgnoreProperties("vacations")
private User user;
}
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;
I am trying some hibernate.The following is the pojo I am using,
#Entity
#Table(name = "person")
public class Person {
#Id
#GeneratedValue
#Column(name = "person_id")
private long person_id;
#Column(name = "name")
private String name;
#Column(name = "Address")
private String Address;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "person" )
private Set<Phone> phone;
//Getters ande Setters
}
#Entity
#Table(name = "phone")
public class Phone{
#Id
#GeneratedValue
#Column(name = "phone_id")
private long phone_id;
#Column(name = "name")
private String name;
#ManyToOne(cascade = CascadeType.MERGE,fetch = FetchType.EAGER)
#JoinColumn(name = "person_id")
private Person person ;
//Getters ande Setters
}
What I want is when I fetch a record from person and need corresponding all phone details. (Like Select * from person) I have around 1360 data in person and nearly double in phone. But for some reason error is thrown. I am not able to see full error stack . Below is the error I am getting.
at
com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:505)
~[jackson-databind-2.4.6.jar:2.4.6] at
com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:639)
~[jackson-databind-2.4.6.jar:2.4.6] at
com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:152)
~[jackson-databind-2.4.6.jar:2.4.6] at
com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:505)
~[jackson-databind-2.4.6.jar:2.4.6] at
com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:639)
~[jackson-databind-2.4.6.jar:2.4.6] at
com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:152)
~[jackson-databind-2.4.6.jar:2.4.6] at
com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:117)
~[jackson-databind-2.4.6.jar:2.4.6] at
com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:23)
~[jackson-databind-2.4.6.jar:2.4.6] at
.....
I was not able to post all error that I got
Using JsonManagedReference and JsonBackReference annotations may solve your problem.
While jackson trying to convert objects to json, visits objects and
their attributes. So if objects have bi-directional relations, for
jackson we need to think about cyclic dependencies. Jackson starts
serialize person and see the phone list and take a phone from list and
start serialize phone and sees person in phone and take person from
phone and start serilize it bla bla bla so this is an endless loop. If
jackson sees these annotations, stops and breaks the loop.
Give it a try as below code;
#Entity
#Table(name = "person")
public class Person {
#Id
#GeneratedValue
#Column(name = "person_id")
private long person_id;
#Column(name = "name")
private String name;
#Column(name = "Address")
private String Address;
#JsonManagedReference
#OneToMany(fetch = FetchType.EAGER, mappedBy = "person" )
private Set<Phone> phone;
// Getters and Setters
}
#Entity
#Table(name = "phone")
public class Phone{
#Id
#GeneratedValue
#Column(name = "phone_id")
private long phone_id;
#Column(name = "name")
private String name;
#ManyToOne(cascade = CascadeType.MERGE,fetch = FetchType.EAGER)
#JoinColumn(name = "person_id")
#JsonBackReference
private Person person;
// Getters and Setters
}
You can alternatively use #JsonIdentityInfo on classes
#Entity
#JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="#id")
#Table(name = "phone")
public class Phone {
}
#Entity
#JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="#id")
#Table(name = "person")
public class Person {
}
I was also getting the same error.
Using #JsonBackReference and #JsonManagedReference was still giving me error so I used #JsonIdentityInfo and it worked like a charm.
Below are my classes :-
BookModel :
#Data
#Entity
#Table(name = "book")
#JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="bookId")
public class BookModel implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "book_id")
private int bookId;
#Column(name="book_name")
private String bookName;
#Column(name="book_author")
private String bookAuthor;
#Column(name="book_publish_date")
private Date bookPublishDate;
#Column(name="book_price")
private double bookPrice;
#OneToMany(mappedBy = "book_model")
List<BookImagesModel> bookImagesModels;
//getters and setters
//default constructor
}
BookImagesModel :
#Data
#Entity
#Table(name = "book_images")
#JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="imageId")
public class BookImagesModel implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "image_id")
private long imageId;
#ManyToOne
#JoinColumn(name = "book_id")
private BookModel book_model;
#Column(name = "image_path")
private String imagePath;
//getters and setters
//default constructor
}
I used Mysql8 database with spring boot.