JPA + hibernate foreign key is null - java

I have 2 tables in my database. I have got a Project which can have multiple builds. One build belongs to one project. Everything works fine, except the foreign key in my build table remains null.
Project
#Entity(name="project")
public class Project implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "projectID")
private Long id;
#Column
#JsonProperty("displayName")
private String name;
#JsonProperty("builds")
#JsonIgnore
#LazyCollection(LazyCollectionOption.FALSE)
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = ("project"))
private Collection<Build> builds;
public Project() {
}
public Project(String name) {
this.name = name;
}
public Collection<Build> getBuilds() {
return builds;
}
public void setBuilds(Collection<Build> builds) {
this.builds = builds;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
}
Build
#Entity(name = "build")
public class Build implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column
#JsonProperty("number")
private Integer number;
#Column
#JsonProperty("url")
private String url;
#JsonBackReference
#ManyToOne
#OnDelete(action = OnDeleteAction.CASCADE)
#JoinColumn(name = "project")
private Project project;
public Build() {
}
public Build(String url, Project project, Integer number) {
this.url = url;
this.project = project;
this.number = number;
}
public Long getId() {
return id;
}
public Integer getNumber() {
return number;
}
public String getUrl() {
return url;
}
public void setId(Long id) {
this.id = id;
}
public void setNumber(Integer number) {
this.number = number;
}
public void setUrl(String url) {
this.url = url;
}
public Project getProject() {
return project;
}
public void setProject(Project project) {
this.project = project;
}
}
Does anyone see the problem?

Using JPA you need explicitly define the Project in your Build object.
Project project = new Project();
Build build = new Build();
build.setProject(project);
project.setBuilds(Collections.singletonList(build));
// now you can persist it
em.persist(project)
From Hibernate documentation:
First, keep in mind that Hibernate does not affect normal Java
semantics. How did we create a link between a Person and an Event in
the unidirectional example? You add an instance of Event to the
collection of event references, of an instance of Person. If you want
to make this link bi-directional, you have to do the same on the other
side by adding a Person reference to the collection in an Event. This
process of "setting the link on both sides" is absolutely necessary
with bi-directional links.

Related

Hibernate. How to select child entities with a several parent fields with writing all it in parent entity

I have a next question: while working with Hibernate 3.3.0 run into a situation when I have two tables with one-to-many relationships and I need to get the list of parents. In each entity must be filled the several fields from the parent table and a list of all children mapped in the parent. For the easiest understanding, I give an example. I have two tables with one-to-many relationships: parent is "recipients" and child is "requisites". And I have two classes whose objects are the rows of these tables. Class for the table of recipients:
#Entity
#Table(name = "recipients")
#JsonFilter(value = "recipientsFilter")
public class POJORecipient implements POJO {
private static final long serialVersionUID = 4436819032452218525L;
#Id
#Column
private long id;
#Version
#Column
private long version;
#Column(name = "client_id")
private long clientId;
#Column
private String inn;
#Column
private String name;
#Column(name = "rcpt_country_code")
private String rcptCountryCode;
#Column(name = "rcpt_passp_ser")
private String rcptPasspSer;
#Column(name = "rcpt_passp_num")
private String rcptPasspNum;
#OneToMany(mappedBy = "recipient", fetch = FetchType.LAZY)
#JsonManagedReference
private Set<POJORequisite> requisites = new HashSet<>();
public POJORecipient(){}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public long getVersion() {
return version;
}
public void setVersion(long version) {
this.version = version;
}
public long getClientId() {
return clientId;
}
public void setClientId(long clientId) {
this.clientId = clientId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getInn() {
return inn;
}
public void setInn(String inn) {
this.inn = inn;
}
public String getRcptCountryCode() {
return rcptCountryCode;
}
public void setRcptCountryCode(String rcptCountryCode) {
this.rcptCountryCode = rcptCountryCode;
}
public String getRcptPasspSer() {
return rcptPasspSer;
}
public void setRcptPasspSer(String rcptPasspSer) {
this.rcptPasspSer = rcptPasspSer;
}
public String getRcptPasspNum() {
return rcptPasspNum;
}
public void setRcptPasspNum(String rcptPasspNum) {
this.rcptPasspNum = rcptPasspNum;
}
public Set<POJORequisite> getRequisites() {
return requisites;
}
public void setRequisites(Set<POJORequisite> requisites) {
this.requisites = requisites;
}
}
and for requisites table:
#Entity
#Table(name = "requisites")
public class POJORequisite implements POJO {
private static final long serialVersionUID = -35864567359179960L;
#Id
#Column
private long id;
#Version
#Column
private long version;
#Column
private String bic;
#Column
private String bill;
#Column
private String comments;
#Column
private String note;
#ManyToOne
#JoinColumn(name = "recipient_id")
#JsonBackReference
private POJORecipient recipient;
public POJORequisite(){}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public long getVersion() {
return version;
}
public void setVersion(long version) {
this.version = version;
}
public String getBic() {
return bic;
}
public void setBic(String bic) {
this.bic = bic;
}
public String getBill() {
return bill;
}
public void setBill(String bill) {
this.bill = bill;
}
public String getComments() {
return comments;
}
public void setComments(String comments) {
this.comments = comments;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
public POJORecipient getRecipient() {
return recipient;
}
public void setRecipient(POJORecipient recipient) {
this.recipient = recipient;
}
}
So, I want to select from the recipients only names and all mapped requisites. Consequently, after the selection, I will have a list of POJORecipient objects and in each object filled only the field "name" and set of POJORequisite objects.
As answer of my question I want to discover one of next: how can I do that with help HQL or Criteria API (the second variant is preferable), or understand it is impossible in Hibernate at all, or that this possibility appeared in later versions (also preferably with example). I'm trying to resolve this question for several months now and will be immensely grateful for any help. All clarifications and advices also will be so helpful. Thanks in advance!!!

Java Spring: My POST method is not inserting the id from my relationship

I'm learning Spring Framework, i followed some tutorials of relationship 1-1, so i defined my models: One Library have one Address.
I send in my body request the library data and the id from the address, the spring create the record, but he can't do the relationship, returning address null and when i make a select in database, the address_id is not saving in the table library
This is what i tried:
My model Library:
#Entity
#Table(name = "Bibliotecas")
public class Library implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String name;
#OneToOne
#JoinColumn(name = "address_id", referencedColumnName = "id")
private Address address;
public Library() {
}
public long getId() {
return this.id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return this.address;
}
public void setAddress(Address address) {
this.address = address;
}
}
My model Address:
#Entity
public class Address {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(nullable = false)
private String location;
public long getId() {
return this.id;
}
public void setId(long id) {
this.id = id;
}
public String getLocation() {
return this.location;
}
public void setLocation(String location) {
this.location = location;
}
#OneToOne(mappedBy = "address", fetch = FetchType.LAZY, optional = false)
private Library library;
}
My repositories:
public interface LibraryRepository extends JpaRepository<Library, Long> {}
public interface AddressRepository extends JpaRepository<Address, Long> {}
My library resource:
#RestController
#RequestMapping(value = "/api")
public class LibraryResource {
#Autowired
LibraryRepository libraryRepository;
#GetMapping("/libraries")
public List<Library> listaBibliotecas() {
return libraryRepository.findAll();
}
#PostMapping("/library")
public Library salvaBiblioteca(#RequestBody Library library) {
return libraryRepository.save(library);
}
}
I do this request in Postman:
{
"name": "library test",
"address_id": 1
}
Obs: i have one address with id 1 in database, but i receive:
{
"id": 5,
"name": "Biblioteca test",
"address": null
}
Why i'm receiving null in my return? And why my register is not saving the address_id?
Please consider the following:
You switched the mapping between address & library
Better to user Hibernate annotations on public fields
Address -> Library getter & setter not implemented
Address entity missing the #table annotation
This must work for you:
Library:
#Entity
#Table(name = "library")
public class Library implements Serializable {
private static final long serialVersionUID = 1L;
private long id;
private String name;
private Address address;
public Library() {
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public long getId() {
return this.id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
#OneToOne(mappedBy = "library", cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false)
public Address getAddress() {
return this.address;
}
public void setAddress(Address address) {
this.address = address;
}
}
Address:
#Entity
#Table(name = "address")
public class Address {
private long id;
private String location;
private Library library;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public long getId() {
return this.id;
}
public void setId(long id) {
this.id = id;
}
#Column(nullable = false)
public String getLocation() {
return this.location;
}
public void setLocation(String location) {
this.location = location;
}
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id")
public Library getLibrary() {
return library;
}
public void setLibrary(Library library) {
this.library = library;
}
}
Better never expose your repositories to controller, you should instead reference a service that has access to repositoryDao.
Use same entity name as table name is better approach.

How to create a many to many relationship with extra columns in jhipster?

The jhipster doesn't support create many to many relationships with extra fields.
What is the best way to create many to many association with extra columns in jhispter? Should i create a two one-to-many relationship with extra fields?
Using JHipster Domain Language (JDL), a #ManytoMany holding extra properties (columns) can be easily achieved using an association entity and two ManyToOne relationships. See below:
entity Foo{
...
}
entity Bar{
...
}
entity FooBarAssociation{
extraProperty1 String
extraProperty2 String
...
}
relationship ManyToOne {
FooBarAssociation{foo} to Foo{bars}
FooBarAssociation{bar} to Bar{foos}
}
You will have to do it manually.
this post describes how: https://hellokoding.com/jpa-many-to-many-extra-columns-relationship-mapping-example-with-spring-boot-maven-and-mysql/
In general, as #Antares42 said, you should create an entity for the Many-To-Many table like so:
first entity:
#Entity
public class Book{
private int id;
private String name;
private Set<BookPublisher> bookPublishers;
public Book() {
}
public Book(String name) {
this.name = name;
bookPublishers = new HashSet<>();
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#OneToMany(mappedBy = "book", cascade = CascadeType.ALL, orphanRemoval = true)
public Set<BookPublisher> getBookPublishers() {
return bookPublishers;
}
public void setBookPublishers(Set<BookPublisher> bookPublishers) {
this.bookPublishers = bookPublishers;
}
}
secound entity:
#Entity
public class Publisher {
private int id;
private String name;
private Set<BookPublisher> bookPublishers;
public Publisher(){
}
public Publisher(String name){
this.name = name;
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#OneToMany(mappedBy = "publisher")
public Set<BookPublisher> getBookPublishers() {
return bookPublishers;
}
public void setBookPublishers(Set<BookPublisher> bookPublishers) {
this.bookPublishers = bookPublishers;
}
}
Join table entity:
#Entity
#Table(name = "book_publisher")
public class BookPublisher implements Serializable{
private Book book;
private Publisher publisher;
private Date publishedDate;
#Id
#ManyToOne
#JoinColumn(name = "book_id")
public Book getBook() {
return book;
}
public void setBook(Book book) {
this.book = book;
}
#Id
#ManyToOne
#JoinColumn(name = "publisher_id")
public Publisher getPublisher() {
return publisher;
}
public void setPublisher(Publisher publisher) {
this.publisher = publisher;
}
#Column(name = "published_date")
public Date getPublishedDate() {
return publishedDate;
}
public void setPublishedDate(Date publishedDate) {
this.publishedDate = publishedDate;
}
}
This entity describes the relationship between Book and Publisher and the extra field is published_date
Let's say you have entities like Movie, Rater and needs a join table Ratings. You can write a JDL script like the following:
entity Movie { title String}
entity Rater { name String}
entity Rating { value Integer} //the extra field
relationship ManyToMany {
Rating{rater(name)} to Rater,
Rating{movie(title)} to Movie
}
save it in file.jdl in the project folder, open cmd type
jhipster import-jdl file.jdl
and you have everything

Getting #Id of lazy-loaded #ManyToOne entity allways returns null

I am using Hibernate 4.3.8.Final and have problem with retrieving #Id property of lazy fetched property: For attached classes calling aidConfiguration.getChipApplication().getId() allways returns null. Other properties, eg. aidConfiguration.getChipApplication().getVersion() returns correctly the value from DB. If chipApplication is not lazy loaded (see the comment in the code), then aidConfiguration.getChipApplication().getId() returns correct non-null value.
What am I dong wrong?
BTW I need it to be lazy.
BaseEntity:
#MappedSuperclass
public class BaseEntity implements Serializable {
#Id
#Column(name = "ID", unique = true)
#Size(min = 1, max = 255)
private String id;
#PrePersist
public final void generateUuid() {
if (this.getId() == null) {
this.setId(UUID.randomUUID().toString());
}
}
public final String getId() {
return id;
}
public final void setId(final String id) {
this.id = id;
}
}
AidConfiguration:
#Entity
#Audited
public class AidConfiguration extends BaseEntity {
#Column
#NotBlank
private String name;
#NotNull
#ManyToOne(fetch = FetchType.LAZY) // if it is EAGER (defaut) then then aidConfiguration.getChipApplication().getId() returns correctly non-null value
private ChipApplication chipApplication;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "aidConfiguration", cascade = CascadeType.ALL) // cascade for auto-saving and deleting items
private List<AidConfigurationItem> aidConfigurationItems;
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
public ChipApplication getChipApplication() {
return chipApplication;
}
public void setChipApplication(final ChipApplication chipApplication) {
this.chipApplication = chipApplication;
}
public List<AidConfigurationItem> getAidConfigurationItems() {
return aidConfigurationItems;
}
public void setAidConfigurationItems(final List<AidConfigurationItem> aidConfigurationItems) {
this.aidConfigurationItems = aidConfigurationItems;
}
}
ChipApplication:
#Entity
#Audited
public class ChipApplication extends BaseEntity {
#Column
#NotBlank(message = "Aid can not be empty")
private String aid;
#Column
#NotBlank(message = "Product can not be empty")
private String product;
#Column
#NotBlank(message = "Version can not be empty")
private String version;
#NotNull(message = "Network is mandatory")
#ManyToOne(fetch = FetchType.LAZY)
private Network network;
#ManyToMany(fetch = FetchType.EAGER)
private List<AidTag> aidTags;
public String getAid() {
return aid;
}
public void setAid(final String aid) {
this.aid = aid;
}
public String getProduct() {
return product;
}
public void setProduct(final String product) {
this.product = product;
}
public String getVersion() {
return version;
}
public void setVersion(final String version) {
this.version = version;
}
public Network getNetwork() {
return network;
}
public void setNetwork(final Network network) {
this.network = network;
}
public List<AidTag> getAidTags() {
return aidTags;
}
public void setAidTags(final List<AidTag> aidTags) {
this.aidTags = aidTags;
}
}
Bit late, but the issue HH-9588 is still unresolved, and I just had the same issue (XML mapping rather than annotations, though).
Could not get the id from the getter when the binding was lazy. Got it when eager or fetch join.
Fixed it by getting rid of the "final" modifier on the getId() accessor. (final here was an attempt to protect the way primary keys/identifiers are defined in the superclass for all the entities)
before :
public abstract class Foo {
Long id;
public final Long getId() {
return id;
}
protected final void setId( Long id ){
this.id = id;
}
...
after :
public abstract class Foo {
Long id;
// No more final
public Long getId() {
return id;
}
// No more final
protected void setId( Long id ){
this.id = id;
}
...
Now, I can get the Id with a lazy binding as well.
Seems to me that this "final" modifier does not allow Hibernate to proxy this accessor as intended. The other accessors being not "final", one can access their values from the proxy.
So, I wonder whether HH-9588 is really a bug or a misunderstanding of the hibernate ways ?
That seems a bug, if you do not miss anything. I would report it on Hibernate's bug tracking system. It would be nice if you would update this answer afterwards with a link to the bug.

hibernate.hbm2ddl.auto=update don't work

I have model. there is this part:
model was mapped by jpa annotations.Everywhere I use fetchType = EAGER. If I load vacancy from database, I have 2 duplicates status_for_vacancy objects.
I use property hbm2ddl.auto = update.
If I make new schema of database and fill data, I haven't duplicates status_for_vacancy objects.
It really?
code:
vacancy:
#Entity
#Table(name = "vacancy")
#XmlRootElement(name="vacancy")
public class Vacancy {
private List<VacancyStatus> statusList = new LinkedList<VacancyStatus>();
#OneToMany(mappedBy = "vacancy", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
public List<VacancyStatus> getStatusList() {
return statusList;
}
public void setStatusList(List<VacancyStatus> statusList) {
this.statusList = statusList;
}
}
status_for_vacancy:
#Entity
#Table(name = "status_for_vacancy")
public class StatusForVacancy extends AbstractStatus {
public StatusForVacancy() {
super();
}
public StatusForVacancy(Integer id, String name) {
super(id, name);
}
}
#MappedSuperclass
#XmlRootElement
public abstract class AbstractStatus {
private Integer id;
private String name;
public AbstractStatus() {
super();
}
public AbstractStatus(String name) {
super();
this.name = name;
}
public AbstractStatus(Integer id, String name) {
super();
this.id = id;
this.name = name;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column (name ="id")
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#Column(name = "name")
#NotEmpty
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
vacancy_status:
#Entity
#Table(name = "vacancy_status")
public class VacancyStatus extends AbstractHistoryStatus {
private Vacancy vacancy;
private StatusForVacancy status;
public VacancyStatus() {
super();
}
public VacancyStatus(Integer id, User author, Date date,
Vacancy vacancy, StatusForVacancy status) {
super(id, author, date);
this.vacancy = vacancy;
this.status = status;
}
#ManyToOne
#JoinColumn(name = "vacancy_id")
public Vacancy getVacancy() {
return vacancy;
}
public void setVacancy(Vacancy vacancy) {
this.vacancy = vacancy;
}
#ManyToOne
#JoinColumn(name = "status_id")
public StatusForVacancy getStatus() {
return status;
}
public void setStatus(StatusForVacancy status) {
this.status = status;
}
}
#MappedSuperclass
public abstract class AbstractHistoryStatus {
private Integer id;
private User author;
private Date date;
public AbstractHistoryStatus() {
}
public AbstractHistoryStatus(Integer id, User author, Date date) {
super();
this.id = id;
this.author = author;
this.date = date;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#ManyToOne
public User getAuthor() {
return author;
}
public void setAuthor(User author) {
this.author = author;
}
#Column(name="creation_date")
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
It is all mapping code for these entities.
in debugger:
both id==500 ==> hibernate understand, that it is same objects.
I try add all data from old database to new database - I get old error(
I fix cause of appearance of this problem. It appearances if I add record to note table:
I highly recommend you write equals() and hashCode() methods. The standard equals()/hashCode() implement referential equality (do 2 objects reference the same memory location). So if hibernate has 2 of the 'same' object in memory, but they don't reference the same memory location then you will see the object show up twice. But if you implement equals() based on primary key being equal, then even if there are two copies of the same object in memory, Hibernate won't give you duplicates.
See the JPA spec:
2.4 Primary Keys and Entity Identity
Every entity must have a primary key. ... The value of its primary key
uniquely identifies an entity instance within a persistence context
and to EntityManager operations
Also see this SO post.

Categories

Resources