The annotation #OneToMany is disallowed for this location trying to use mapped by to join a manytoone to a onetomany - spring

The code is this one. As the title says i want to join a ManyToOne to a OneToMany.
#OneToMany(cascade = CascadeType.ALL,mappedBy = "libro"
#ManyToOne
#JoinColumn(name = "id_libros", referencedColumnName = "id_libros")
#JsonIgnoreProperties({"copias"})
private Libro libro;

Related

Query result Infinite Recursion on ManyToMany relationship on hibernate

I have a entity mapping like this:
As you can see it is the bidirectional relationship and the team_users table has it own primary key and extra column - active.
Key code in team entity:
#OneToMany(mappedBy = "team", fetch = FetchType.LAZY)
private Set<TeamUsers> team_users = new HashSet<TeamUsers>();
Key code in user entity:
#OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
private Set<TeamUsers> team_users = new HashSet<TeamUsers>();
Key code in team_user entity:
#ManyToOne(fetch = FetchType.LAZY, optional = false, cascade = CascadeType.ALL)
#JoinColumn(name = "TEAM_ID")
private Team team;
#ManyToOne(fetch = FetchType.LAZY, optional = false, cascade = CascadeType.ALL)
#JoinColumn(name = "USER_ID")
private User user;
I have a API which will return all team information, then I have service class like:
#Autowired
private TeamRepository teamRepo;
public List<Team> listAll() {
return (List<Team>) teamRepo.findAll();
}
Then the chrome log me that I have a "undefined" value, and when I test it by postman it shows me the infinite loop value:
I want to figure out what is the best approach to fetch the data?
I want to all information that tells me the team situation, including team... users...active status , almost everthing.
Any suggestions?
update
I tried to use #JsonIgnore on intermidate table :
#JsonIgnore
#ManyToOne(fetch = FetchType.LAZY, optional = false, cascade = CascadeType.ALL)
#JoinColumn(name = "TEAM_ID")
private Team team;
#JsonIgnore
#ManyToOne(fetch = FetchType.LAZY, optional = false, cascade = CascadeType.ALL)
#JoinColumn(name = "USER_ID")
private User user;
but I won't get user information in that case and it avoid infinite loop:
What else I can do to get all information for teams?

Hibernate mapping user relation to entities

Let's se we have Hibernate entity User with basic fields such as username, password, roles etc..
Now we have an entity such as Car.
User has a OneToOne relationship with Car, cause he can own a car. But he also has besides this a OneToMany relationship to Car, because he also owns the cars of his children. But in the frontend I want to know which cars he owns for himself and which cars he owns for his children. The same applies to the relationship between User and motorbike (his own, his childrens, etc...)
How would the User entity class look like? Is it good to have the relationships mapped in an "Helper" entity such as UserData:
#Entity
#Data
#Table( name = "users",
uniqueConstraints = {
#UniqueConstraint(columnNames = "username")
})
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotBlank
#Size(max = 150)
private String username;
#NotBlank
#Size(max = 120)
private String password;
#OneToOne(cascade = {CascadeType.ALL}, fetch = FetchType.EAGER)
#JoinColumn(name = "USER_DATA_ID")
private UserData userData;
UserData:
#Entity
#Data
#Table( name = "user_data")
public class UserData {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToOne(cascade = {CascadeType.ALL}, fetch = FetchType.EAGER)
#JoinColumn(name = "OWN_CAR_ID")
private Car ownCar;
#OneToOne(cascade = {CascadeType.ALL}, fetch = FetchType.EAGER)
#JoinColumn(name = "PARTNER_CAR_ID")
private Car partnerCar;
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable( name = "user_children_cars",
joinColumns = #JoinColumn(name = "user_data_id"),
inverseJoinColumns = #JoinColumn(name = "car_id"))
private Set<Car> childrenCars = new HashSet<>();
public boolean addToChildrenCarSet(Car c) {
return childrenCars.add(c);
}
public UserData() {
}
}
As you ask for an opinion, I would say it gets unnecessary complicated if you use the intermediate entity user_data. :-) There is no real drawback to add more fields and keys into the user class - performance is probably also better then using the EAGER fetching. If performance is an issue, better optimize querys later on then splitting the table now.
Also the #ManyToMany I would avoid - better create the intermediate table and relations yourself. You can check out https://bootify.io and create your database schema there. There is no EAGER fetching and also no CascadeType.ALL (both only good ideas in special cases), you would probably add more problems with that then actual helping in any way.
So the addToChildrenCarSet method would end up in a #Service class, in a method with #Transactional, in my proposal.

JPA Repository - Getting duplicates in List caused by table joins

I am having a very difficult situation and yet the situation is very complex and hard to find similar case in stackoverflow.
I have the following entities
Store
#Data
#Entity
#Table(name = "store")
public class Store implements IModel {
#Id
#EqualsAndHashCode.Exclude
#GeneratedValue(strategy = GenerationType.AUTO)
private UUID id;
#Enumerated(EnumType.STRING)
#Column(name = "storestatus", nullable = false)
private StoreStatus storeStatus = StoreStatus.UNKNOWN;
#OneToOne
#JoinColumn(name = "storetypecode_id")
private StoreTypeCode storeTypeCode;
#OneToOne(cascade = CascadeType.ALL, mappedBy = "store")
private Address address;
#Setter(AccessLevel.NONE)
#EqualsAndHashCode.Exclude
#OneToMany(fetch = FetchType.EAGER, mappedBy = "store")
private Set<StoreTranslation> storeTranslationList = new HashSet<>();
public Store() {
}
StoreTypeCode
#Data
#Entity
#Table(name = "storetypecode")
public class StoreTypeCode implements IModel {
#Id
#EqualsAndHashCode.Exclude
#GeneratedValue(strategy = GenerationType.AUTO)
private UUID id;
#Column(name = "displaysort", nullable = false)
private Integer displaySort = 999;
#Setter(AccessLevel.NONE)
#EqualsAndHashCode.Exclude
#OneToMany(fetch = FetchType.EAGER, mappedBy = "storeTypeCode")
private Set<StoreTypeCodeTranslation> storeTypeCodeTranslationList = new HashSet<>();
public StoreTypeCode() {
}
}
And StoreCategory
#Data
#Entity
#Table(name = "storeitemcategory")
public class StoreItemCategory implements IModel {
#Id
#EqualsAndHashCode.Exclude
#GeneratedValue(strategy = GenerationType.AUTO)
private UUID id;
#ManyToOne
#JoinColumn(name = "store_id")
private Store store;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(
name = "storeitemcategory_storeitem",
joinColumns = {#JoinColumn(name = "storeitemcategory_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "storeitem_id", referencedColumnName = "id")})
private List<StoreItem> storeItems = new ArrayList<>();
#Setter(AccessLevel.NONE)
#EqualsAndHashCode.Exclude
#OneToMany(fetch = FetchType.EAGER, mappedBy = "storeItemCategory")
private Set<StoreItemCategoryTranslation> storeItemCategoryTranslationList = new HashSet<>();
public StoreItemCategory() {
}
public void addStoreItem(StoreItem storeItem) {
this.storeItems.add(storeItem);
}
}
With the above relationship, here is what I have.
Store A with storeTypeCode ("Cafe") and storeItemCategory ("Iced drinks")
StoreTypeCode has two translations 1) for English, 2) for Chinese.
Whenever I add an item to storeItems in StoreItemCategory, I get duplicates in the list. (And multiple duplicate records are inserted to 'storeitemcategory_storeitem' table.)
StoreItemCategory sic = storeItemCategoryRepository.findById(storeItemCategoryid).get();
sic.addStoreItem(new StoreItem(...));
sic = storeItemCategoryRepository.save(sic);
I suspect this has something to do with the way tables are joined for translations because when I run a query created from Spring for getting StoreItemCategory, I get multiple records of StoreItemCategory (one for English and one for Chinese from StoreTypeCode).
select
*
from
storeitemcategory storeitemc0_
left outer join
store store1_
on storeitemc0_.store_id=store1_.id
left outer join
storetranslation storetrans2_
on store1_.id=storetrans2_.store_id
left outer join
storetypecode storetypec3_
on store1_.storetypecode_id=storetypec3_.id
left outer join
storetypecodetranslation storetypec4_
on storetypec3_.id=storetypec4_.storetypecode_id
left outer join
address address5_
on store1_.id=address5_.store_id
left outer join
storeitemcategorytranslation storeitemc6_
on storeitemc0_.id=storeitemc6_.storeitemcategory_id
left outer join
storeitemcategory_storeitem storeitems7_
on storeitemc0_.id=storeitems7_.storeitemcategory_id
left outer join
storeitem storeitem8_
on storeitems7_.storeitem_id=storeitem8_.id
left outer join
store store9_
on storeitem8_.store_id=store9_.id
left outer join
storeitemtranslation storeitemt10_
on storeitem8_.id=storeitemt10_.storeitem_id
where
storeitemc0_.id=?
All my tables will have translations tables and I am not sure how to get-around with this without using set.
Does anyone have similar experience?

Spring Crud on Nested Property

I have a spring crud repository:
#Repository
public interface CrudCVVacancyMatchRepository extends CrudRepository<CVVacancyMatchEntity, Long> {
The CVVacancyMatchEntity object has an Vacancy property. I'm trying to write a query method on properties of the Vacancy property.
The following query method works fine (Vacancy has a string property called name):
Iterable<CVVacancyMatchEntity> findByVacancyName(String name);
But Vacancy also has properties as a set:
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(name = "vacancy_industries", joinColumns = { #JoinColumn(name = "fk_vacancy", referencedColumnName = "id") }, inverseJoinColumns = { #JoinColumn(name = "fk_industry", referencedColumnName = "id") })
private final Set<IndustryEntity> industries = Sets.newHashSet();
This doesn't work:
Iterable<CVVacancyMatchEntity> findByVacancyIndustries(Set<IndustryEntity> industryEntities);
I get ERROR SqlExceptionHelper:146 - Syntax error in SQL statement
select cvvacancym0_.id as id1_19_, cvvacancym0_.comment as comment2_19_, cvvacancym0_.cv_id as cv_id4_19_, cvvacancym0_.rating as rating3_19_, cvvacancym0_.user_id as user_id5_19_, cvvacancym0_.vacancy_id as vacancy_6_19_ from cv_vacancy_match cvvacancym0_ cross join vacancy vacancyent1_ cross join vacancy_industries industries2_, industry industryen3_ where cvvacancym0_.vacancy_id=vacancyent1_.id and vacancyent1_.id=industries2_.fk_vacancy and industries2_.fk_industry=industryen3_.id and .=? [42001-182]
Any idea?

JPA many to many - do i have to remove\add from both collection sets?

I have a User entity,
And a Department Entity
i want to have #manyToMany relationship between them :
many users can have many departments.
in my User entity:
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "UserDepartments", joinColumns = { #JoinColumn(name = "user_id", referencedColumnName = "id") }, inverseJoinColumns = { #JoinColumn(name = "department_id", referencedColumnName = "id") })
private Set<Department> departments;
and my Department entity has a SET as well of users..
my question is:
if i need to implement the method :
public void removeUserFromDepartment(User user, Department department) {
//bla bla
}
do i have to call
department.getUserCollection.remove(user);
AND
user.getDepartmentCollection.remove(department);
Or is there a way to maintain this logic by only removing one of them ?
If i have to save both its pretty hard to maintain especially for someone who doesn't know about the many to many relation of the two entities..
When a OneToMany or ManyToMany relationship exists in JPA the client code is responsible for managing the relationship. This means that you must explicitly remove the object from both sides of the relationship.
So lets say you have a User instance and need to remove a department.
User user = dao.findUser(1L); //Find a user, psuedo code
Department dept = user.getDepartments().get(0);
dept.getUsers().remove(user);
user.getDepartments().remove(user);
dao.update(user); //once again psuedo code
To use the code above you should add a cascade type to the relationship in the user entity:
#ManyToMany(fetch = FetchType.LAZY, cascade=CascadeType.ALL)
#JoinTable(name = "UserDepartments", joinColumns = { #JoinColumn(name = "user_id", referencedColumnName = "id") }, inverseJoinColumns = { #JoinColumn(name = "department_id", referencedColumnName = "id") })
private Set<Department> departments;
This will cause saves on the User entity to be cascaded to the Departments entity. Just a reminder save is psuedo code, it will boil down to a call on the EntityManager such as persist or merge.

Resources