I have two tables: authors and books
Author:
#Entity
#Table (name="authors")
public class Author implements java.io.Serializable {
private Integer id;
private String name;
private String lastName;
/*book list*/
private Set<Book> books= new HashSet<Book>(0);
public Author() {
}
public Author(String name, String lastName) {
this.name = name;
this.lastName = lastName;
}
public Author(String name, String lastName, Set<Book> books) {
this.name = name;
this.lastName = lastName;
this.books = books;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "AUTHOR_ID", unique = true, nullable = false)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#Column(name = "AUTHOR_NAME", unique = true, nullable = false, length = 10)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Column(name = "AUTHOR_LASTNAME", unique = true, nullable = false, length = 10)
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "author")
public Set<Book> getBooks() {
return books;
}
public void setBooks(Set<Book> books) {
this.books = books;
}
}
Book:
import javax.persistence.*;
#Entity
#Table(name = "books")
public class Book implements java.io.Serializable {
private Integer id;
private String name;
private Author author;
public Book() {
}
public Book(String name) {
this.name = name;
}
public Book(String name, Author author) {
this.name = name;
this.author = author;
}
#Id
#Column(name = "BOOK_ID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#Column(name = "BOOK_NAME")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "AUTHOR_ID",nullable = false)
public Author getAuthor() {
return author;
}
public void setAuthor(Author author) {
this.author = author;
}
}
In my book's table I have field with id author. How can I get all books from one author? How Can I solve it?
Must I use HQL or other methods? I am beginner in this.
first you need to the mapping between two entities.
Author class
#OneToMany(mappedBy="author")
private Set<Book> books= new HashSet<Book>(0);
Book class
#ManyToOne
private Author author;
after that you can use a simple criteria query to retrieve the relevant records.
I wont help you with the code here but the logic..
The very first thing you need to do is build a relationship between Author and Books using the annotations #OneToMany or #ManyToOne depending on your structure.
Next use the Author Class Object to retrive the list of Books.
Related
Recently I switched into Spring Data JPA and I am wondering how is it possible to save a new object into the database with some default values.
In my example I have to save a book into my database, but, in the owner column, I need to put the value 0.
So, this how I did that with JDBC, and it works amazingly well.
public void save(Book book){
jdbcTemplate.update("INSERT INTO book(name,author,yearOfProduction,owner) VALUES (?, ?, ?, 0)",
book.getName(),book.getAuthor(),book.getYearOfProduction());
}
Now I want to do the same with Spring Data JPA. Here is my save function:
BookService
#Transactional
public void save(Book book)
{
bookRepository.save(book);
}
I have two objects: Person and Book. The relationships are: one person can have many books and one book has one owner. Here are my Person and Book classes:
Book
#Entity
#Table(name = "book")
public class Book {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id",nullable = false)
private int id;
#Column(name="name")
#NotEmpty(message = "Book name can't bee empty")
private String name;
#Column(name="author")
#NotEmpty(message = "Author name can't bee empty")
private String author;
#Column(name="yearOfProduction")
#NotNull(message = "Year of production can't bee empty")
#Min(value = 0,message = "year must be more than 1900")
private int yearOfProduction;
#ManyToOne
#JoinColumn(name = "owner_id", referencedColumnName = "id")
private Person owner;
public Book(String name, String author, int yearOfProduction) {
this.name = name;
this.author = author;
this.yearOfProduction = yearOfProduction;
}
public Book(){
}
public Person getOwner() {
return owner;
}
public void setOwner(Person owner) {
this.owner = owner;
}
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;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public int getYearOfProduction() {
return yearOfProduction;
}
public void setYearOfProduction(int yearOfProduction) {
this.yearOfProduction = yearOfProduction;
}
}
Person|
#Entity
#Table(name = "person")
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
#Column(name = "name")
#NotEmpty(message = "Please enter the name")
#Size(min = 1, max = 30, message = "Length must be 2-30 symbols")
//make regex with ФИО;
private String name;
#Column(name = "ageOfBirth")
#Min(value = 0, message = "age of birth must be more than 0")
private int ageOfBirth;
#OneToMany(mappedBy = "owner")
private List<Book> books;
public Person() {
}
public Person(String name, int ageOfBirth) {
this.name = name;
this.ageOfBirth = ageOfBirth;
}
public List<Book> getBooks() {
return books;
}
public void setBooks(List<Book> books) {
this.books = books;
}
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;
}
public int getAgeOfBirth() {
return ageOfBirth;
}
public void setAgeOfBirth(int ageOfBirth) {
this.ageOfBirth = ageOfBirth;
}
}
I guess this is impossible to make with Spring Data JPA? So, I made it with by adding JdbcTemplate and I definitely think it is a hard-coding approach to use Spring DATA and JdbcTemplate together.
It's also unable to make with database. Down below i am using the default definition of postgres and still get null's when create a new book.
https://www.baeldung.com/jpa-default-column-values
create table book(
id int primary key generated by default as identity,
name varchar(250) not null,
author varchar(250) not null,
yearOfProduction int not null,
owner_id int default 0 references person(id)
)
#egeorge answered my question. It is impossible to input 0 into owner table.
Since 0 has a special value, and is not a real person record, there should not be any value in that field. null is the appropriate value for a join column that is not joined to an actual record. You will need to change the logic that interprets 0 as "free" to check for null instead. (I am surprised your database let you do that to begin with. Foreign key constraints will normally reject a value that is not present in the referred table.)
I have the following scenario:
I have a Student class and students table.
I have Course class and courses table.
Every student and course have unique ID.
I would like to put a List into the Student class which is mapped by courses IDs.
I have tried a lot of annotations and relations but nothing succeeded
#Entity
#Table(name = "courses")
public class Course {
private long id;
private String name;
public Course() {
}
public Course(String name, int size) {
this.name = name;
this.size = size;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
#Column(name = "name", nullable = false)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
#Entity
#Table(name = "students")
public class Student {
private long id;
private String name;
#OneToMany(cascade = CascadeType.ALL)
private List<Course> courses = new ArrayList<>();
public Student() {
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
#Column(name = "name", nullable = false)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Course> getCourses() {
return courses;
}
public void setCourses(List<Course> courses) {
this.courses = courses;
}
}
Can you help me hot to achieve that because i am a little newbie into the spring
Use the following when declaring one to many relation
#Column(name="course_id")
private Set<Course> courses;
You need to use OneToMany annotation.
#OneToMany(mappedBy = "students", cascade = CascadeType.ALL)
private List<Course> courses;
You need to give your list a type. For instance
List<Courses> courseList = new ArrayList<>();
Given an Enitiy Product
#Entity
public class Product {
private Long id;
private List<Review> reviews;
public Product() {}
#Id
#GeneratedValue
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
#ElementCollection
public List<Review> getReviews() {
return reviews;
}
public void setReviews(List<Review> reviews) {
this.reviews = reviews;
}
// equals() and hashCode() omitted for brevity
}
And an Embeddable Review
#Embeddable
public class Review {
private Customer author;
private String title;
private String comment;
public Review() {}
#ManyToOne(optional = false)
#Column(unique = true)
public Customer getAuthor() {
return author;
}
public void setAuthor(Customer author) {
this.author = author;
}
#Column(nullable = false)
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
#Column(nullable = false, length = 2000)
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
}
How can I set an unique constraint for the Review's author. In other words: I want to make sure, that for a given product each review has a different author.
Can I use #NaturalId? Do I use #Column(unique = true)? I already found a similar question on StackOverflow, but in my case it's a list of Embeddables and not just a member, so that that approach won't work, I guess.
Thanks a lot in advance!
If you are talking about having a unique database index added during schema generation then you can do this as below:
#ElementCollection
#CollectionTable(name = "product_reviews",
uniqueConstraints = {#UniqueConstraint(columnNames={"product_id", "author_id"})})
public List<Review> getReviews() {
return reviews;
}
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
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.