how to count items of OneToMany element via Spring data - java

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);

Related

Query for tables with #ManyToMany relation(Hibernate)

I rewrite my SpringMVC app with using Hibernate.I try to make query for selecting lectures for group of students by id of group.with using SQL query(before I started rewrite it with using Hibernate)this query was:
"SELECT * FROM lectures WHERE id IN (SELECT lecture_id FROM lectures_groups WHERE group_id =?) ORDER BY date_of_lecture"
I have Lecture and Group etities:
#Entity
#Table(name = "lectures")
public class Lecture {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "lectures_groups", joinColumns = #JoinColumn(name = "lecture_id"), inverseJoinColumns = #JoinColumn(name = "group_id"))
private List<Group> groups = new ArrayList<>();
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "teacher_id")
private Teacher teacher;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "subject_id")
private Subject subject;
#Column(name = "date_of_lecture")
private LocalDateTime date;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "audience")
private Audience audience;
public Lecture() {
}
//getters setters
}
and:
#Entity
#Table(name = "groups")
public class Group {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "group_name")
private String name;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "cathedra_id", referencedColumnName = "id")
private Cathedra cathedra;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "lectures_groups", joinColumns = #JoinColumn(name = "group_id"), inverseJoinColumns = #JoinColumn(name = "lecture_id"))
private List<Lecture> lectures = new ArrayList<>();
public Group() {
}
//getters setters
}
I tried somthing like:
List<Lecture> lectures = session.createQuery("select l from lectures l join l.groups g where g.id=:groupId")
.setParameter("groupId", group.getId())
.list();
but I get Exception: org.hibernate.hql.internal.ast.QuerySyntaxException: lectures is not mapped
So how can i do it?
In hql query you need to provide the name of the entity in the query instead of the table name. So in your case, you should replace lectures with Lecture in the query.
List<Lecture> lectures = session.createQuery("select l from Lecture l join l.groups g where g.id=:groupId")
.setParameter("groupId", group.getId())
.list();

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.

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;
}

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

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=? ) ;

Categories

Resources