I have this model class:
public class Usuario {
...
#OneToMany(fetch = FetchType.EAGER)
#Fetch(FetchMode.SELECT)
private List<org.loja.model.credencial.Credencial> credenciais;
...
}
If I add this annotation to this attribute:
#JoinColumn(unique=false)
causes the table usuario_credenciais not being created on database (it is when the annotation is omitted, but causes problems during runtime due to the uniqueness situation).
What I can do to solve that?
I solve that changing the OneToMany annotation to ManyToOne, getting this:
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name="usuario_credenciais", joinColumns={#JoinColumn(name="usuario_id")}, inverseJoinColumns={#JoinColumn(name="credencial_id")})
#Fetch(FetchMode.SELECT)
private List<org.loja.model.credencial.Credencial> credenciais;
Now the table is created on the database, and the application allows multiple users have the same credentials.
Related
I have such a case where I need to have internally many-to-one using hibernate proxies and only id externally, here using MapsId. The issue appears when I try to save something, because the target entity is not fetched, when I set the value only on the id.
Let's take an example: I have an Account table and DeviceConfig table. Inside the DeviceConfig's class definition, I add account in a many-to-one relation and accountId in relation with #MapsId.
Now when creating, I always set a value to accountId, but never the value is picked up, and the backend throws an SQL error, because the field cannot be null.
#Table(name = "djl_device_config")
#Entity
#Getter
#Setter
#ToString
#RequiredArgsConstructor
public class DeviceConfig extends CoreEntity {
...
#JsonIgnore
#ManyToOne
#MapsId("accountId")
#JoinColumn(name = "account_id")
private Account account;
#Column(name = "account_id", insertable = false, updatable = true, nullable = true)
private UUID accountId;
}
So I suppose this is a config error on my side, but I've been reading the JPA for these three days and I still don't know what's wrong or what I should do to achieve the behaviour I expect.
That for any help you'll provide.
My User class looks like this :
#Data
#Entity
public class User {
#Id
Long userID;
#ManyToMany(mappedBy = "admins")
private List<ClassRoom> classRooms = new ArrayList<>();
}
And my ClassRoom class like this :
#Data
#Entity
public class ClassRoom {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
Long classRoomID;
#ManyToMany
#JoinTable(name ="classroom_user",
joinColumns = #JoinColumn(name = "classroom_id"),
inverseJoinColumns = #JoinColumn(name = "user_id"))
private List<User> admins = new ArrayList<>();
}
And in my UserController class, I have :
#PostMapping("user/{id}/c")
User addClassRoom(#PathVariable Long id,#RequestBody ClassRoom newClassRoom)
{
logger.debug(repository.findById(id));
return repository.findById(id)
.map(user -> {
user.getClassRooms().add(newClassRoom);
user.setClassRooms(user.getClassRooms());
return repository.save(user);
})
.orElseGet(() -> {
return null;
});
}
And I POST and empty JSON ({}) and I see no change in my users. The Classroom or an empty Classroom doesn't get added in the User.
What is the problem here? How can I resolve this ?
user.getClassRooms().add(newClassRoom); is suffice, user.setClassRooms(user.getClassRooms()); not required.
You will have to perform cascade save operation.List all cascade types explicitly and don't use mappedBy, instead use joincolumns annotation.
Can you paste the logs, please? Is Hibernate doing any insert into your table? Has the database schema been created in the DB correctly? One thing I recommend you to do is to add a custom table name on the top of your User class, using annotations like so: #Table(name = "users"). In most SQL dialects user is a reserved keyword, hence it is recommended to always annotate User class a bit differently, so that Hibernate won't have any problems to create a table for that entity.
IMO you must find classRoom by its id from repository, if it's new, you must create a new entity and save it first. Then assign it to user and save it.
The object you receive from the post method was not created by the entity manager.
After using user.getClassRooms().add(newClassRoom);
We must use userRepository.save(user);
I am trying to implement the OneToOne association in JPA and trying to join two tables using spring boot and spring data JPA. I created one spring boot microservice and implemented the one to one association in my model. But when I am running code I am getting the following error ,
Caused by: org.hibernate.AnnotationException: Illegal attempt to map a non collection as a #OneToMany, #ManyToMany or #CollectionOfElement
Here My First model class Users.java is like following,
#Entity
#Table(name = "users")
public class Users implements Serializable {
private static final long serialVersionUID = 9178661439383356177L;
#Id
#Column(name="user_id")
public Integer userId;
#Column(name="username")
public String username;
#Column(name="password")
public String password;
}
And I am testing association by controller using following code,
#GetMapping("/load")
public Users load() {
return (Users) userObj.findAll();
}
Can anyone help to resolve this association issue please ?
This is wrong.
#OneToOne(mappedBy="nuserId")
public Set<UserRoleMapping> roleUserRoleMappingMappingJoin;
}
OneToOne means only one object..right?
See this for mappings understandings.
https://docs.jboss.org/hibernate/orm/3.6/reference/en-US/html/collections.html#collections-persistent
Annotation #OneToOne defines a single-valued association to another entity, and in your case you associate a user to a Set of UserRoleMapping instead of associating it with a single object of that class. Use #ManyToOne annotation
Actually the exception refers to an invalid #OneToMany, #ManyToMany or #CollectionOfElement mapping
and this can only be
#OneToMany()
#JoinColumn(name="nuser_id" , referencedColumnName="nuserId")
public Users nuserId;
If the #OneToMany relation is valid change this at first to
#OneToMany()
#JoinColumn(name="nuser_id" , referencedColumnName="nuserId")
public List<Users> users;
If the #OneToMany relation is NOT valid change this to
#OneToOne()
#JoinColumn(name="nuser_id" , referencedColumnName="nuserId")
public Users users;
I am planning to store data from multiple tables which has one to many JPA relationship. I am creating my Repository interface which extends from JPARepository. My question is If I want to save a data on Many sides of relationship (in the below scenario it's Tour) then shall I do with TourRepository or PersonRespository?
On a similar note Is it ideal to create individual repository classes for every JPA entities where data need to be stored? or any better way with limited repository classes the data store to database can be achieved?
#Entity
#Table(name="Person")
public class Person implements Serializable{
...
...
#OneToMany(mappedBy = "person")
private List<Tour> tours;
...
#Entity
#Table(name = "Tour")
public class Tour implements Serializable{
...
...
#ManyToOne
#JoinColumn(name = "PERSON_ID")
private Person person;
...
You have two independent entities. Person can exist without Tour and Tour can exist without Person. So you should have two repositories - for Person and Tour to store their data independently:
Tour tour1 = new Tour("tour1");
tourRepo.save(tour1);
Person person1 = new Person("person1");
person1.addTour(tour1);
personRepo.save(person1);
You chose the bidirectional one-to-many association so you have to use a 'helper' method like addTour to link both entities:
public Person addTour(Tour tour) {
tour.setPerson(this);
this.tours.add(tour);
return this;
}
Additional info: Best Practices for Many-To-One and One-To-Many Association Mappings
Add cascade to tours:
#OneToMany(mappedBy = "person", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
private List<Tour> tours;
When you save person object, his tours will be saved automatically.
By the way, in Person class, you should have an addTour(...) utilities method like this:
// Person.java
public void addTour(Tour tour){
this.tours.add(tour);
tour.setPerson(this);
}
I would suggest you to use CascadeType.ALL on #OneToMany mapping in Person entity:
#OneToMany(mappedBy = "person",cascade = {CascadeType.ALL})
private List<Tour> tours;
And then create repository for person to save person object with the list of tours .
CascadeType.ALL means persistence will propagate all EntityManager operations like PERSIST, REMOVE, REFRESH, MERGE, DETACH to the relating entities.
Yet another thread like this. I fighting with this for 4 days.
annotation #Getter and #Setter are from lombok plugin
My Place class
#Entity
public class Place {
#Getter
#Setter
#OneToMany(mappedBy = "place", targetEntity = Tag.class, cascade = CascadeType.ALL)
private Set<Tag> tags;
//...
}
Tag class which should be many
#Entity
public class Tag {
#Getter
#Setter
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "fk_place_id")
private Place place;
//...
}
I'm saving it like this
Tag tagOne = new Tag("tagOne");
Tag tagTwo = new Tag("tagTwo");
Set<Tag> tagSet = new HashSet<>();
tagSet.add(tagOne);
tagSet.add(tagTwo);
Place place = new Place();
place.setTags(tagSet);
placeService.save(place);
saving looks is the single line sessionFactory.getCurrentSession().persist(entity) on every case. Saving entity with #OneToOne mapping it works like a charm.
You have a bidirectional association. You're initializing only one side of the association, and that side is the inverse side (because it has the mappedBy attribute). Hibernate only cares about the owner side. So, for Hibernate, there is no association between the tags and the place.
Note that cascade=ALL on a ManyToXxx association doesn't make sense. If 100 tags are referencing the same place, and you delete one of these tags, you don't want to also delete the place. And even if you want to, that won't work, because 99 other tags still reference it, which will cause a referential integrity error.