Hibernate create wrong query on joining 'many to many' association - java

Here is my entity classes:
AccService.java
#ManyToMany(mappedBy = "accServices")
private List<BaseSpecification> baseSpecifications;
#ManyToMany(mappedBy = "accServices")
private List<IndustrySpecification> industrySpecifications;
BaseSpecification.java
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "BASE_SPEC_SERVICES",
joinColumns = {#JoinColumn(name = "SPEC_ID", referencedColumnName = "ID")},
inverseJoinColumns = {#JoinColumn(name = "SRV_ID", referencedColumnName = "ID")})
private List<AccService> accServices;</code>
IndustrySpecification.java
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "IND_SPEC_SERVICES",
joinColumns = {#JoinColumn(name = "SPEC_ID", referencedColumnName = "ID")},
inverseJoinColumns = {#JoinColumn(name = "SRV_ID", referencedColumnName = "ID")})
private List<AccService> accServices;</code>
And I'm making query using Criteria API:
Criteria criteria = session.createCriteria(BaseSpecification.class);
criteria.createAlias("accServices", "as");
criteria.createCriteria("as.industrySpecifications", "asis", JoinType.LEFT_OUTER_JOIN, Restrictions.eq("asis.id", industrySpecId));
Hibernate generates following query, which fails because of using wrong alias in first 'left outer join' clause
select this_.name as y0_, asis3_.name as y1_,
from BASE_SPEC this_
inner join BASE_SPEC_SERVICES accservice5_ on this_.id=accservice5_.SPEC_ID
inner join ACC_SERVICE as2_ on accservice5_.SRV_ID=as2_.id
left outer join IND_SPEC_SERVICES industrysp7_ on as2_.id=industrysp7_.SRV_ID and ( asis3_.id=? )
left outer join INDUSTRY_SPEC asis3_ on industrysp7_.SPEC_ID=asis3_.id and ( asis3_.id=? ) ;

Related

how to count items of OneToMany element via Spring data

i have a user Entity :
#Entity
#Table(name = "user")
#Data
public class UserEntity extends BaseEntity {
#Column(name = "full_name")
private String fullName;
....
#OneToMany(cascade = CascadeType.REMOVE)
#JoinTable(name = "user_post",
joinColumns = {#JoinColumn(name = "user_id")},
inverseJoinColumns = {#JoinColumn(name = "post_id")})
private Set<PostEntity> posts;
#ManyToMany
#JoinTable(name = "user_followers",
joinColumns = {#JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "follower_id", referencedColumnName = "id")})
private Set<UserEntity> followers = new HashSet<>();
#ManyToMany
#JoinTable(name = "user_followings",
joinColumns = {#JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "following_id", referencedColumnName = "id")})
private Set<UserEntity> followings = new HashSet<>();
}
now i want to count followers of a user.
i can get list of followers and use list.size() but this is not good . i just want count of them not whole objects .is this possible by a method in my UserRepostiory that extends JpaRepostiory or a native query ?
I suggest you to use JPQL syntax. In your UserRepository you can add count methods. Please try :
#Query("select count(p) from User u join u.posts p where u.id = ?1")
long countPosts(Long id);
#Query("select count(f) from User u join u.followers f where u.id = ?1")
long countFollowers(Long id);
#Query("select count(f) from User u join u.followings f where u.id = ?1")
long countFollowings(Long id);

QueryException: could not resolve property

Here is my two pojo fields
#ManyToMany
#Cascade(value = SAVE_UPDATE)
#JoinTable(name = "catalogToCatalog",
joinColumns = {#JoinColumn(name = "parentId",
foreignKey = #ForeignKey(ConstraintMode.NO_CONSTRAINT))},
inverseJoinColumns = {#JoinColumn(name = "childId",
foreignKey = #ForeignKey(ConstraintMode.NO_CONSTRAINT))})
private List<Catalog> parents;
#Cascade(value = SAVE_UPDATE)
#ManyToMany(mappedBy = "parents", fetch = FetchType.EAGER, targetEntity = Catalog.class)
private List<Catalog> children;
How I could get data with named query like
"from Catalog c left join c.parents p " +
"where p.parentId = :parentId";
?
QueryException: could not resolve property: parentId of: com.x.model.Catalog [from com.x.model.Catalog c left join

Referential integrity constraint violation - failing when add more then 2 records

When im loading my initial tests data i retrieve integrity constraint violation exception. It only occurs, when im adding more then 2 records, using addShift method. Im using h2, in memory database.
Loading:
public void load() {
shiftService.addShift(1, LocalDate.now(), ShiftType.DAY, 1);
shiftService.addShift(2, LocalDate.now().plusDays(1), ShiftType.NIGHT, 1);
shiftService.addShift(2, LocalDate.now().plusDays(5), ShiftType.NIGHT, 2);
}
Shift Service:
#Transactional
public void addShift(long userId, LocalDate shiftDate, ShiftType shiftType, long groupId) {
Optional<User> user = userService.findOne(userId);
if (user.isPresent()) {
Optional<Group> group = groupService.getOne(groupId);
if (group.isPresent()) {
Shift shift = new Shift(shiftDate, shiftType, group.get());
user.get().addShift(shift);
}
}
}
Caused by:
org.h2.jdbc.JdbcSQLException: Referential integrity constraint
violation: "FKG5R8KJRL3GG3EKESMHT77GO7L: PUBLIC.SHIFT FOREIGN KEY(ID)
REFERENCES PUBLIC.GROUPS(ID) (3)"; SQL statement:
insert into shift (id, group_id, shift_date, shift_type) values (null, ?, ?,
?) [23506-196]
Model:
Shift:
#Entity
public class Shift {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private LocalDate shiftDate;
private ShiftType shiftType;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "user_shifts", joinColumns = #JoinColumn(name = "shift_id", referencedColumnName = "id"), inverseJoinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"))
private Set<User> users = new HashSet<>();
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "group_id")
private Group group;
Group:
#Entity
#Table(name = "groups") // Group is reserved name in SQL
public class Group {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String name;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "user_group", joinColumns = #JoinColumn(name = "group_id", referencedColumnName = "id"), inverseJoinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"))
private Set<User> users = new HashSet<>();
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "moderator_group", joinColumns = #JoinColumn(name = "group_id", referencedColumnName = "id"), inverseJoinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"))
private Set<User> moderators = new HashSet<>();
#OneToMany(mappedBy = "id", cascade = CascadeType.ALL)
private Set<Shift> shifts;
User:
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String email;
private String password;
private String firstName;
private String lastName;
private String phone;
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(
name = "user_authority",
joinColumns = {#JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "authority_name", referencedColumnName = "name")}
)
private Set<Authority> authorities = new HashSet<>();
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(
name = "user_group",
joinColumns = {#JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "group_id", referencedColumnName = "id")}
)
private Set<Group> usingGroups = new HashSet<>();
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(
name = "moderator_group",
joinColumns = {#JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "group_id", referencedColumnName = "id")}
)
private Set<Group> moderatingGroups = new HashSet<>();
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(
name = "user_shifts",
joinColumns = {#JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "shift_id", referencedColumnName = "id")}
)
private Set<Shift> shifts = new HashSet<>();
Do you have any ideas why i got this exception?
Your mapping in Group is wrong.
#OneToMany(mappedBy = "id", cascade = CascadeType.ALL)
private Set<Shift> shifts;
This should be rather:
#OneToMany(mappedBy = "group", cascade = CascadeType.ALL)
private Set<Shift> shifts;
Explanation:
Hibernate is adding a foreign key constraint between id in shift and id in group. You are probably adding 2 groups, and after you try to add more than 2 shifts, the constraint isn't fulfilled, because a group with id 3 doesn't exist.

How to Ignore a whole Mapped/Joined Model(Class) in Spring hibernate.

I have three tables. tbl_vendor and tbl_category tables are mapped using #ManyToMany relation. When I am getting 'Vendors' under a particular 'Category' I am also getting 'Areas' because tbl_vendor and tbl_area are also mapped using #ManyToMany.
relations:
in tbl_vendor Model :
#ManyToMany(cascade = CascadeType.DETACH, fetch = FetchType.LAZY)
#JoinTable(name = "tbl_category_vendor", joinColumns = {#JoinColumn(name = "vendor_id")}, inverseJoinColumns = {#JoinColumn(name = "category_id")})
private Set<Category> categories = new HashSet<>();
....
#ManyToMany(cascade = CascadeType.DETACH, fetch = FetchType.LAZY)
#JoinTable(name = "tbl_area_vendor", joinColumns = {#JoinColumn(name = "vendor_id")}, inverseJoinColumns = {#JoinColumn(name = "area_id")})
private Set<Area> areas = new HashSet<>();
in tbl_category Model :
#JsonIgnore
#ManyToMany(cascade = CascadeType.DETACH, mappedBy = "categories", fetch = FetchType.LAZY)
private List<Vendor> vendors = new ArrayList<>();
in tbl_area Model :
#JsonIgnore
#ManyToMany(mappedBy = "areas", fetch = FetchType.LAZY)
private List<Vendor> vendors = new ArrayList<>();
I have a particular case where I don't need this 'Area' with 'Vendor'.
is there any way to ignore already mapped 'Area' from 'Vendor' using JpaRepository in some particular case ?

Hibernate multiple attribute mappings same table deletion

I have a hopefully simple problem in Hibernate. I have Users and Projects. The users_projects (in my case user_project_association) has an extra attribute "role" to say if the user is project leader or normal user.
#OneToMany(mappedBy = "project", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
#LazyCollection(LazyCollectionOption.EXTRA)
private Set<UserProjectAssociation> userProjectAssociations = new HashSet<>();
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "user_project_role",
joinColumns = #JoinColumn(name = "project_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"))
#WhereJoinTable(clause = "role_id=7")
#Setter(AccessLevel.NONE)
private Set<User> projectLeaders = new HashSet<>();
#ManyToMany
#JoinTable(name = "user_project_role",
joinColumns = #JoinColumn(name = "project_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"))
#LazyCollection(LazyCollectionOption.EXTRA)
#Setter(AccessLevel.NONE)
private Set<User> users = new HashSet<>();
If i try to remove a project via "getEntityManager().remove(persistentInstance);" I can see in the log this sql statements:
Hibernate:
/* delete collection com.XXX.core.model.Project.users */ delete
from
user_project_role
where
project_id=?
Hibernate:
/* delete collection com.XXX.core.model.Project.projectLeaders */ delete
from
user_project_role
where
project_id=?
and (
role_id=7
)
Hibernate:
/* delete com.XXX.core.model.UserProjectAssociation */ delete
from
user_project_role
where
id=?
and the error message:
2016-05-25 10:05:57 INFO AbstractBatchImpl:208 - HHH000010: On release of batch it still contained JDBC statements
and nothing is deleted. Does anyone have an idea to get my projects deleted?
Thanks a lot :)
Puh. I found (the or a) solution for it. It's not really elegant, but it's working:
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "user_project_role",
joinColumns = #JoinColumn(name = "project_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"))
#WhereJoinTable(clause = "role_id=7")
#SQLInsert(sql = "insert into user_project_role (project_id, user_id, role_id) values (?, ?, 7)")
#SQLDelete(sql = "delete from user_project_role where project_id=? and user_id=? and role_id = 7")
#Setter(AccessLevel.NONE)
private Set<User> projectLeaders = new HashSet<>();
#ManyToMany
#JoinTable(name = "user_project_role",
joinColumns = #JoinColumn(name = "project_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"))
#LazyCollection(LazyCollectionOption.EXTRA)
#WhereJoinTable(clause = "role_id=8")
#SQLInsert(sql = "insert into user_project_role (project_id, user_id, role_id) values (?, ?, 8)")
#Setter(AccessLevel.NONE)
private Set<User> projectUsers = new HashSet<>();
So I removed the userProjectAssociations attribute and added customized #SQLInsert and #SQLDelete Statements.
If I want to get all Users including normal users and project leaders I use this method:
public Set<User> getAllUsers() {
Set<User> allUsers = new HashSet<>();
allUsers.addAll(projectLeaders);
allUsers.addAll(projectUsers);
return allUsers;
}

Categories

Resources