Jpa OneToOne shared primary key half works - spring-boot

I have SpringBoot 2.1.3 and Java 8 application. Building DB with JPA I have 3 table in one to one relationship. Suppose the tables is the follows:
#Entity
#Data //lombok
#Table(name = "users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#OneToOne(mappedBy = "user", cascade = CascadeType.ALL)
private Address address;
}
And then:
#Entity
#Data
#Table(name = "address")
public class Address {
#Id
#Column(name = "id")
private Long id;
#OneToOne
#MapsId
private User user;
}
That's works.. and it is the best way to do (this exactly example is taken from documentation).
If I start the application the DB is created and if I tried to add entities all works well. The model created follows:
Now I want to add a Country object to my address Entities (for example) and I modified the Entities as follows:
#Entity
#Data
#Table(name = "address")
public class Address {
#Id
#Column(name = "id")
private Long id;
#OneToOne
#MapsId
private User user;
#OneToOne
#MapsId
private Country country;
}
And Country Entities:
#Entity
#Data
#Table(name = "country")
public class Country {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#OneToOne(mappedBy = "country", cascade = CascadeType.ALL)
private Address address;
}
The application still starts, the DB is created and the model follows:
But if I try to save a User as follows:
User user = new User();
Address address = new Address();
Country country = new Country();
user.setAddress(address);
address.setUser(user);
address.setCountry(country);
country.setAddress(address);
userRepository.save(user);
I obtain the error:
java.sql.SQLException: Field 'country_id' doesn't have a default value
Anyway I solve the issue removing #MapsId and added #JoinColumn but I would like to understand what's wrong.
P.S.: I'm using MySQL 5.7 with InnoDB dialect (setting on application.properties)
Thanks all

It works only with one #MapsId annotation. Using two is causing that country id is not inserted:
insert into Country (id) values (?)
insert into Users (id) values (?)
insert into Address (user_id) values (?)

Related

Save entity with realtion

I have two entities with one-to-mane relationship:
#Entity
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
#JsonManagedReference
private List<RealEstate> realEstates = new ArrayList<>();
#Entity
public class RealEstate implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private String name;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "user_id")
#JsonBackReference
private User user;
I try to save realEstate entity with this code:
realEstate.setUser(user);
realEstateService.saveRealEstate(realEstate);
And this response:
[
{
"id": 1,
"name" : "Bueno",
"user" : 1
}
]
By all I have is creating new record in user table and relation with this new ID.
What I do wrong? What I need to read about this?
You first need to save User entity record and then RealEstate entity record.
Please read this article to implement One To Many relationship. I am sure your issue will be resolved.
https://attacomsian.com/blog/spring-data-jpa-one-to-many-mapping

Spring data jpa hibernate one to may duplicate issue

I have one to many relation ship between a User and UserRole.
public class User {
#Id
#GeneratedValue
private long id;
#Column(unique = true)
private String username;
private String password;
#OneToMany(fetch=FetchType.EAGER)
#JoinTable(
name = "user_roles",
joinColumns = {#JoinColumn(name="userId")},
inverseJoinColumns = {#JoinColumn(name="roleId")}
)
private Collection<UserRole> roles;
}
and
public class UserRole {
#Id
#GeneratedValue
private long id;
#Column(unique = true)
private String roleName;
}
I am able to save a user at first. But when I try to save another user it rejects with an exception of duplicated entry on the junction table
One thing I noticed is when we have One-to-Many association the many side foreign key will be a primary key on the junction table. So, I need to make the relation Many-to-Many. So that the combination of both foreign keys will serve as a composite key.

spring data - how to make unique constraint with custom logic?

using spring data, I created User 1:N UserDog N:1 Dog relation. Both 1:N relations are unidirectional #ManyToOne with UserDog being the custom relation table.
User entity:
#Entity
public class User {
#Id
#GeneratedValue
private long id;
#Column(nullable = false)
private String name;
}
Dog entity:
#Entity
public class Dog {
#Id
#GeneratedValue
private long id;
#Column(nullable = false)
private String name;
}
User dog relation table:
#Entity
public class UserDog {
#Id
#GeneratedValue
private long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn
#OnDelete(action = OnDeleteAction.CASCADE)
private User user;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn
#OnDelete(action = OnDeleteAction.CASCADE)
private Dog dog;
#Column(nullable = false)
private Instant createdOn = Instant.now();
#Column
private Instant disabledOn;
}
Use case
Use case is to store history of User-Dog bindings, where the concrete Dog can be bound only to one User at the time. That's why I added createdOn and disabledOn columns to UserDog. disabledOn being null indicates that the relation is active and the Dog can't be assigned another User. If disabledOn is not null, then the record is stored only for evidence purposes and the Dog can be assigned to the same or another User again.
Question
How to ensure that the combination of Dog's id and disabledOn being null is unique in UserDog table?
In pseudo code I want something like this:
#Entity
#UniqueConstraint({#UniqueConstraint(this.dog.id), #NullConstraint(this.disabledOn)})
public class UserDog {...}
You can simply create a unique constraint for dogId and disabledOn.
It does add the limitation that no two relationships may end at the same time but this seems to fit your use case.

JPQL query / JPA / Spring boot best practice of updating many to many table

I have a user table and a city table and I have a connecting table users_cities (columns: id, user_id, city_id). A user can follow multiple cities.
From the client side i send an array of cityIds. Some might be new some might still be selected and some might have been deselected.
What is a best practice to update the users_cities table with the data? Should I just delete everything for that particular userId and insert the new array or ... ?~
Also, how does one delete and repsectively insert the data in bulk, for a many to many reference?!
#Getter
#Setter
#NoArgsConstructor
#ToString
#Accessors(chain = true)
#Entity
#Table(name = "users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(unique = true)
private String email;
private String password;
private Boolean isGuest;
#ManyToMany(fetch = FetchType.EAGER)
private Set<Role> roles;
#ManyToOne()
#JoinColumn(name = "country_following_id")
private Country countryFollowing;
#ManyToMany()
private Set<City> citiesFollowing;
#ManyToMany()
private Set<Offer> offersFollowing;
}
and
#Getter
#Setter
#NoArgsConstructor
#ToString
#Accessors(chain = true)
#Entity
#Table(name = "cities")
public class City {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#NonNull
private Long id;
private String countryCode;
private String name;
#Latitude
private Double latitude;
#Longitude
private Double longitude;
}
Should I just delete everything for that particular userId and insert the new array
Since the relation connecting users and cities does not have an identity of its own, that sounds reasonable
Also, how does one delete and repsectively insert the data in bulk, for a many to many reference?
Just clear the User.citiesFollowing collection and populate it anew (hint: since you have cityIds at the ready, you can use EntityManager.getReference() to load the cities)

Inner join on two tables in spring boot

I have 2 entities and want to perform an inner join on the ID of these two tables. How do I do that? After joining the tables, how do I get the values?
First entity: Employee.java
#Entity
#Table(name = "emp")
public class Employee {
#Id
#Column(name = "id", nullable = false)
private int id;
#Column(name = "language", nullable = false)
private String language;
Second entity: Username.java
#Entity
#Table(name = "users")
public class Username {
#Id
#Column(name = "id", nullable = false)
private int id;
#Column(name = "name", nullable = false)
private String name;
Thanks
I don't know it's helpful for your or not but,
You have to give relationship between those table first(Here i defined bidirectional relationship).
I suppose there is #OneToOne mapping. As like follow,
In Employee Table,
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "username_id")
private Username username;
#OneToOne(mappedBy = "employee")
private Employee employee;
Same way whenever you need those data base on requirement then Place Query as following way in your Employee Repository,
#Query(nativeQuery = true, value="<your-join-query>")
public Employee getEmployeeAllDetails();
For more brief detail follow this kind of tutorials which give you better idea regurding working mechenisum.
https://howtodoinjava.com/
https://www.baeldung.com/

Resources