MEMBER OF in EJB-QL 3 doesn't work - java

I would like to retrieve many 'Access' which have one 'Role' in common.
It's the named query:
SELECT access
FROM Access AS access
WHERE :role MEMBER OF access.listRole
The Access entity
public class Access implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String name;
private String libelle;
#ManyToOne
private Module oneModule;
#ManyToMany
private List<Role> listRole;
/* Setter & Getter */
}
The Role entity
public class Role implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String name;
private String description;
#Enumerated(EnumType.STRING)
private Flag oneFlag;
#Transient
private int lengthAccess;
#OneToMany(mappedBy="oneRole")
private List<UserAccount> listUserAccount;
#ManyToMany
private List<Access> listAccess;
/* Geter & Setter */
}
But I don't achieve to do the right EJB-QL !
Configuration:
EJB 3
MySQL (InnoDB)
jBoss
Plop
Thanks.

I cannot reproduce the problem. When running the JPQL query you provided, like this:
String qlString = "SELECT access " +
"FROM Access AS access " +
"WHERE :role MEMBER OF access.listRole";
Role role = new Role();
role.setId(1L);
List accesses = session.createQuery(qlString).setParameter("role", role).list();
Hibernate generates the following SQL query for me (I simplified a bit your entities by removing some attributes):
select
access0_.id as id127_,
access0_.libelle as libelle127_,
access0_.name as name127_
from
Access access0_
where
? in (
select
role2_.id
from
Access_ROLES listrole1_,
ROLES role2_
where
access0_.id=listrole1_.Access_id
and listrole1_.listRole_id=role2_.id
)
Everything seems correct (tested with Hibernate Core 3.3.0.SP1, Hibernate Annotations 3.4.0.GA, Hibernate EM 3.4.0.GA)
What version of Hibernate (Core, Annotations, EntityManager) are you using exactly? What error do you get exactly? Can you show how you invoke the query?

My link #ManyToMany between my two classes isn't write in the right way, during the project's building, 2 Tables has created in MySQL ("access_role" for my link #ManyToMany in the 'access' class, and role_access for my link #ManyToMany in the 'role' class)
So, to correct this, I modified like this
public class Access implements Serializable {
// ...
#ManyToMany(mappedBy="listAccess")
private List<Role> listRole;
// ...
}
public class Role implements Serializable {
// ...
#ManyToMany
#JoinTable(name = "access_role",
joinColumns = #JoinColumn(name = "role_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "access_id", referencedColumnName = "id"))
private List<Access> listAccess;
// ...
}

Related

How to stop Hibernate from eagerly fetching a relationship when it is mapped using a column (referencedColumnName) different than the primary key?

I'm mapping a relationship that does not use the entity's primary key. Using "referencedColumnName" with a column different than the primary key causes hibernate to eagerly fetch the association, by issuing an extra select, even when it's tagged with FetchType.LAZY.
My goal is to make it behave like a regular mapping, meaning it wouldn't issue an extra query every time I need to query the main entity.
I have already tried using #LazyToOne(LazyToOneOption.NO_PROXY), which sorts out the problem, but it does not operate well with Jackson's (JSON parsing library) module "jackson-datatype-hibernate5", which skips hibernate lazy proxies when serializing the results.
Here is a scenario almost like the one I have that causes the problem:
Entities:
#Entity(name = "Book")
#Table(name = "book")
public class Book
implements Serializable {
#Id
#GeneratedValue
private Long id;
private String title;
private String author;
#NaturalId
private String isbn;
//Getters and setters omitted for brevity
}
#Entity(name = "Publication")
#Table(name = "publication")
public class Publication {
#Id
#GeneratedValue
private Long id;
private String publisher;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(
name = "isbn",
referencedColumnName = "isbn"
)
private Book book;
#Column(
name = "price_in_cents",
nullable = false
)
private Integer priceCents;
private String currency;
//Getters and setters omitted for brevity
}
Repository (Spring-Data, but you could try directly with the EntityManager):
#Repository
public interface PublicationRepository extends JpaReadRepository <Publication, Long>
{
#Query ("SELECT d FROM Publication d WHERE d.publisher = ?1 ")
Optional <Publication> findByPublisher (String isbn);
}
Thanks
The only way to achieve what you are looking for is by moving the annotatation #Id to the isbn property.
You can leave the #GeneratedValue on the autoincrement property.
Notes:
1 - Make sure that your equals/hc are following the OID(Object ID) on your domain case the "NaturalId" ISBN.
2 - It will be good to ensure if possible on DB level that your natural ID has unique contraint on it.

Spring Boot / JPA / mySQL - many to one relationship creates too many SQL queries

I have a simple spring boot rest app connected with mySQL db and I'm trying to optimize number of queries within simple function:
List<Message> messages = messagesRepository.findBySenderIdOrReceiverIdOrderByTimeDesc(senderId, receiverId);
MessagesRepository:
public interface MessagesRepository extends CrudRepository<Message, Long> {
List<Message> findBySenderIdOrReceiverIdOrderByTimeDesc(Long senderId, Long receiverId);
}
Message:
#Entity
#Table(name="s_messages")
public class Message implements Serializable
{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#Transient
private int internalId;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name="senderId", referencedColumnName = "id", updatable=false, insertable=false)
private ProfileLite sender;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name="receiverId", referencedColumnName = "id", updatable=false, insertable=false)
private ProfileLite receiver;
#Column(columnDefinition="TEXT")
private String message;
private long time;
private MessageStatus status;
}
ProfileLite:
#Entity
#Table(name="s_profiles")
public class ProfileLite implements Comparable<ProfileLite>
{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String nickname;
private String country;
private String thumb;
private Gender gender;
}
After executing method mentioned above, hibernate generates about 40 SQL's (based on 40 profiles) like this:
SQL Log - PasteBin
so first collecting messages and then for each message creates another sql to gather profile.
Is it any possibility to push hibernate to create just one simple sql instead of 40 like: select * from s_messages m join s_profiles s1 on m.sender_id = s1.id join s_profiles s2 m_receiver_id = s2.id ? (pseudo code)
Thanks!
This could be a n + 1 problem.
You can use a JOIN FETCH in your JPA query to fix this.
A "fetch" join allows associations or collections of values to be initialized along with their parent objects using a single select. This is particularly useful in the case of a collection. It effectively overrides the outer join and lazy declarations of the mapping file for associations and collections.
Update your JPA repository like so
public interface MessagesRepository extends CrudRepository<Message, Long> {
#Query("Select m from Message m join fetch m.sender ms join fetch m.receiver mr where ms.id = :senderId or mr.id = :receiverId order by m.time desc")
List<Message> findBySenderIdOrReceiverIdOrderByTimeDesc(Long senderId, Long receiverId);
}
For a more detailed explanation check out this answer.
PS: I havent tested the query.

JPA Hibernate :: Inheritance of an entity, with additional OneToMany Lists

I'm using JPA Hibernate/Spring boot to build a web server with MySQL database, and I'm trying to extend a POJO Entity that looks like this, with additional OneToMany Lists.
#Entity
#Table(name="user")
public class User {
#Id
#GeneratedValue
private Integer id;
#Column(nullable=false)
private String name;
....Constructors, getters and setters....
}
with this basic user entity, I just wanna make a UserInfo entity with additional information about the user's careers.
#Entity
public class UserInfo extends User {
#OneToMany(cascade= CascadeType.ALL, fetch= FetchType.EAGER)
#JoinColumn(name="user_id", referencedColumnName = "id")
private List<Career> careers;
....Constructors, getters, setters......
}
And I'm quite confused which inheritance strategy I should choose. I don't think its necessary to make another column or table for this.
Or should I just query twice..?
I'm kinda new to JPA so not sure which is considered as the best practice or design..
Edit:
This is how Career entity looks like. Just in case..
#Entity
#Table(name="career")
public class Career {
#Id
#GeneratedValue
private Integer id;
#Column(nullable=false)
private Integer user_id;
#Column(nullable=false)
private String name;
#Column(nullable=false)
private String description;
....Constructors, getters and setters....
}
Since extending User table was meaningless(just in my case), I changed the User class like this.
#Table(name="user")
public class User {
#Id
#GeneratedValue
private Integer id;
#Column(nullable=false)
private String name;
#OneToMany(fetch= FetchType.LAZY)
#JoinColumn(name="user_id", referencedColumnName = "id")
private List<Career> careers;
....Constructors, getters, setters......
}
Now I'm trying this with Spring Data JPA, and when I try to show the list of Users with their Careers, it is now querying more than 40 times taking about a minute to show the result.
Is this the N+1 problem..? how can I solve this?
In my opinion the error lies within the model itself. Why should UserInfo extend User? I cannot imagine which attributes or methods the UserInfo should inherit from a User. Typical inheritances would be "Developer" or "Administrator".
Why don't you add UserInfo as a 1:1 relation in your User entity? Another option is to omit UserInfo and put the Careers as a 1:n relation right into your User.
To prevent possible n+1 issues on a growing number of Careers you might want to change the fetch mode. See below
#OneToMany(fetch=FetchType.LAZY,mappedBy="user")
#Fetch(FetchMode.SUBSELECT)
private Set<Career> careers = new HashSet<>();

Hibernate #Where annotation on a ManyToOne relation

I have recently started to refactor my project because I had to add an extra column to some of my table. The extra column is an Enum (Pending, or Active).
Because of that change I would need now to refactor ALL my queries to only retrieves a row if the status is ACTIVE.
After some research I found that we can annotate an Entity with the #Where annotation. it works fine where I use it on a simple column but my table look like this:
#Where(clause = 'state='ACTIVE'")
#Entity
public class Place {
#Column(name="id_place")
private String placeId;
#Column(name="name")
private String palceName;
#OneToMany(mappedBy = "place")
private Set<PlaceTag> placeTag;
...
...
}
#Where(clause = 'state='ACTIVE'")
#Entity
public class Tag {
#Column(name="id_tag")
private String tagId;
#Column(name="name")
private String tagName;
#OneToMany(mappedBy = "tag")
private Set<PlaceTag> placeTag;
...
...
}
#Where(clause = 'poi.state='ACTIVE' AND tag.state='ACTIVE")
#Entity
public class PlaceTag {
#Column(name="id")
private String id;
#ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY)
#JoinColumn(name = "place_id")
private Place place;
#ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY)
#JoinColumn(name = "tag_id")
private Tag tag;
...
...
}
Now my question would be how can make this statement ONLY return the places and tags that are ACTIVE ?
SELECT pt FROM PlaceTag pt;
Is this possible? Or will I have to write the query Explicitly ?
Thank you
As you already discovered, or simply use cases the #Where clause is just fine, but in your case, you want to filter PlaceTag by the place and tag too, so a joined is required in this situation.
So, you can keep the #Where clause for Place and Tag, while for PlaceTags you need to use a JPQL query:
select pt
from PlaceTag pt
join pt.tag t
join pt.place p
where
t.state='ACTIVE' and p.state='ACTIVE'
At least until #WhereJoinTable annotation is made to work for many-to-one associations too.

JPA 2 Hibernate mapping with composite key in primary key using #IdClass with 3 tier structure

This question is very similar to: JPA (Hibernate, EclipseLink) mapping: why doesn't this code work (chain of 2 relationships using JPA 2.0, #EmbeddedId composite PK-FK)?
Actually my only (from meaningful that I spotted) difference is that I use #IdClass and that I most probably won't be able to switch to a different provider than hibernate.
but anyway here is the code (removed parts that where unimportant):
PermissionContextType.java:
#Entity
#IdClass(PermissionContextTypePk.class)
public class PermissionContextType{
#Id
private String id;
#Id
#JoinColumn (name = "PROJECT", referencedColumnName = "ID")
#ManyToOne ()
private Project project;
public static class PermissionContextTypePk implements Serializable{
public String project;
public String id;
// ... eq and hashCode here ...
}
}
PermissionContext.java:
#Entity
#IdClass(PermissionContextPk.class)
public class PermissionContext{
#Id
private String id;
#Id
#JoinColumns ({
#JoinColumn (name = "PROJECT", referencedColumnName = "PROJECT"),
#JoinColumn (name = "PERMISSIONCONTEXTTYPE", referencedColumnName = "ID")
})
#ManyToOne
private PermissionContextType permissionContextType;
public static class PermissionContextPk implements Serializable{
public String id;
public PermissionContextTypePk permissionContextType;
// ... eq and hashCode here ...
}
}
Permission.java:
#Entity
#IdClass(PermissionPk.class)
public class Permission{
#Id
private String id;
#Id
#JoinColumns ({
#JoinColumn (name = "PROJECT", referencedColumnName = "PROJECT"),
#JoinColumn (name = "PERMISSIONCONTEXTTYPE", referencedColumnName = "PERMISSIONCONTEXTTYPE"),
#JoinColumn (name = "PERMISSIONCONTEXT", referencedColumnName = "ID")
})
#ManyToOne
private PermissionContext permissionContext;
public static class PermissionPk implements Serializable{
public String id;
public PermissionContextPk permissionContext;
// ... eq and hashCode here ...
}
}
and what I get is:
org.hibernate.AssertionFailure: Unexpected nested component on the referenced entity when mapping a #MapsId: PermissionContext
Caused by: org.hibernate.AssertionFailure: org.hibernate.AssertionFailure: Unexpected nested component on the referenced entity when mapping a #MapsId: PermissionContext
does anybody know if this is a hibernate bug and I should post it on their issue tracking system (and pray that I would be able to update to given hibernate version) or is there something fundamentally wrong with my way of binding the entities?
I've checked it with the hibernate implementation on EAP 6.1 (4.2.0) as well as on wildfly (don't really know which one.)
Ok, so this is what I found so far :
Thanks fr my friend : https://hibernate.atlassian.net/browse/HHH-5764 which most probably is the reason for this behaviour.
And I found a workaround :
Permission.java:
#Entity
#IdClass(PermissionPk.class)
public class Permission{
#Id
private String id;
// for the next 3 fields there are no public acessors, so the public API of the class was not changed !
#Id
#Column(name = "PROJECT")
private String projectId;
#Id
#Column(name = "PERMISSIONCONTEXTTYPE")
private String permissionContextTypeId;
#Id
#Column(name = "PERMISSIONCONTEXT")
private String permissionContextId;
#JoinColumns ({
#JoinColumn (name = "PROJECT", referencedColumnName = "PROJECT", updatable = false, insertable = false),
#JoinColumn (name = "PERMISSIONCONTEXTTYPE", referencedColumnName = "PERMISSIONCONTEXTTYPE", updatable = false, insertable = false),
#JoinColumn (name = "PERMISSIONCONTEXT", referencedColumnName = "ID", updatable = false, insertable = false)
})
#ManyToOne
private PermissionContext permissionContext;
public static class PermissionPk implements Serializable{
// previously they where private as well, but removed public constructor for the sake of simplicity of the question - so no changes where necesary in public API of the class !
private String id;
private String projectId;
private String permissionContextTypeId;
private String permissionContextId;
public PermissionPk () {}
public PermissionPk (String aId, PermissionContextPk aPermissionContext) {
this.id = aId;
permissionContextId = aPermissionContext.id;
permissionContextTypeId = aPermissionContext.permissionContextType.id;
projectId = aPermissionContext.permissionContextType.project;
}
... eq and hashCode here ...
}
}
The good thing about this workaround is that it does not change the public API of the class in any way
(the only change was that I needed to make fields in Pk's of context and contexttype visible to the PermissionPk - they where private before with only a public constructor [but again simplified for the question]), nor did it change the jpql queries, and at the same time workaround is scalable (to any tier amount - as long as every even pk does not contain another pk), so if the bug will be resolved it will be easy to remove the workaround.
I would still gladly accept any comments on either my workaround or the question in itself.
Today I found another workaround :)
You can omit #IdClass entirely and use hibernate specific ability to create composite keys on the fly as apparently it is not affected by this bug.
The drawback here is that:
it is entirely Hibernate specific not covered by JPA at all.
you cannot do em.find(ClassName.class,new ClassPk(args...)) as there is no ClassPk at all.
But if you could use anything else than hibernate you could just as well use something without this bug - so probably 1 is not a problem really. and there is a possibility that you don't really need the em.find for this entity (or can live with creating it thru session or jpql query).

Categories

Resources