I have 2 entity
BlackList
public class BlackList {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id", unique = true, nullable = false)
private Integer id;
#ManyToOne
#JoinColumn(name = "applicant_id", unique = true)
private Applicant applicant;
and
public class Applicant {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id", unique = true, nullable = false)
private Integer id;
#Column(name = "number", nullable = false, unique = true)
private String number;
please help me. How create criteria for get me data for this query: select applicant.number from black_list inner join applicant on black_list.applicant_id = applicant.id
public List<BlackList> getAll(){
Session session =sessionFactory.getCurrentSession();
ProjectionList projectionList = Projections.projectionList();
Criteria criteria = session.createCriteria(BlackList.class);
projectionList.add(Projections.property("applicant"));
criteria.setProjection(projectionList);
List res = criteria.list();
return res;
}
this method returned me /id and number/ but i need only number
There are two ways to approach this, you could select the applicants from the black list using hql.Or you could add the inverse join in your applicant, allowing you to 'create alias' and add a 'not null' restriction.
Related
I'm newbie
I'm trying pass this Postgres query to JPA/JPQL
SELECT
DISTINCT(srv.code) AS Serv_Cod,
srv.id AS Serv_id,
srv.description AS Serv_Desc
FROM db.Category AS cat
join db.Classification AS cla ON cat.id = cla.cat_id
join db.Service AS srv ON srv.id = cla.srv_id
WHERE cat.id = 10
ORDER BY srv.id;
Now I want to write the same Query, I have the Entities with the same name Table.
Classification
#Entity
#Table(name = "Classification", schema = "db")
#Audited
public class Classification implements Identifiable<Long> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "srv_id", nullable = true)
private Service service;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "cat_id", nullable = true)
private Category category;
....
}
Service
#Entity
#Table(name = "Service", schema = "db")
#Audited
public class Service implements Identifiable<Long> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
#Column(name = "code", nullable = false)
private String code;
#Column(name = "description", nullable = false)
private String description;
....
}
I was reading, but I'm very confused...
I don't know how to write the ON for the JOIN, and establish the DISTINCT for a Column/Field.
Long myID = 25L;
this.em.createQuery("SELECT NEW SomeDto(srv.id, srv.code, srv.description)"
+ " FROM Classification cla"
+ "JOIN cla·cat_id cat"
+ "JOIN cla·srv_id srv"
+ "WHERE cat.id = :id"
,BaseObjectDto.class).setParameter("id", myID).getResultList();
Thank you for you valuable Help.
The query is very simple. When you have ToOne relationships you can navigate to the related entity. There is no need to JOIN ON.
Even with ToMany there is no need for the ON because this is already defined in the mapping.
So the query will look like:
SELECT NEW SomeDto(cla.service.id, cla.service.code, cla.service.description)
FROM Classification cla
WHERE category.id = :id
I have got the following Entities, an item which can has up to two categories, a primary and a secondary.
Both categories are mapped ManyToOne to the category table using a JoinColumnsOrFormulas.
The first one gets fetched EAGER as expected, but the second one does not occur in the SQL statement and gets lazy loaded.
This lazy loading results in a classical n+1 problem.
This is my item entity with the both category entities which should gets joined:
#Entity
#Table(name = "item", schema = "public", catalog = "stackoverflow_question")
#DynamicUpdate
public class Item extends StackOverflowQuestionEntity {
#Id
#Column(name = "id")
protected Long id;
#Column(name = "site")
private String site;
#ManyToOne
#JoinColumnsOrFormulas({
#JoinColumnOrFormula(formula = #JoinFormula(value = "site", referencedColumnName = "site")),
#JoinColumnOrFormula(formula = #JoinFormula(value = "primary_category_id", referencedColumnName = "category_id"))
})
private Category primaryCategory;
#Column(name = "primary_category_id")
private Long primaryCategoryId;
#ManyToOne
#JoinColumnsOrFormulas({
#JoinColumnOrFormula(formula = #JoinFormula(value = "site", referencedColumnName = "site")),
#JoinColumnOrFormula(formula = #JoinFormula(value = "secondary_category_id", referencedColumnName = "category_id"))
})
private Category secondaryCategory;
#Column(name = "secondary_category_id")
private Long secondaryCategoryId;
}
This is the category entity:
#Entity
#Table(name = "category", schema = "public", catalog = "stackoverflow_question")
public class Category extends StackOverflowQuestionEntity {
#Column(name = "category_id")
private Long categoryId;
#Column(name = "name")
private String name;
#Column(name = "site")
private String site;
}
The resulting query contains only the primary category:
SELECT this_.id AS id1_9_9_,
this_.inserted AS inserted2_9_9_,
this_.updated AS updated3_9_9_,
this_.primary_category_id AS formula174_9_,
this_.secondary_category_id AS formula176_9_,
category2_.id AS id1_0_0_,
category2_.inserted AS inserted2_0_0_,
category2_.updated AS updated3_0_0_,
category2_.name AS name7_0_0_
FROM public.item this_
LEFT OUTER JOIN public.category category2_ ON this_.site=category2_.site
AND this_.primary_category_id=category2_.category_id
WHERE True;
Hence the secondary category get joined lazy:
SELECT category0_.id AS id1_0_0_,
category0_.inserted AS inserted2_0_0_,
category0_.updated AS updated3_0_0_,
category0_.name AS name4_0_0_,
category0_.site AS site5_0_0_
FROM public.category category0_
WHERE category0_.site=?
AND category0_.category_id=?;
Why is Hibernate joining the secondary category lazy, the annotations seems the be the same.
The hibernate version I am using is 5.0.10.Final.
This is how the base entity looks like:
#MappedSuperclass
abstract public class StackOverflowQuestionEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, insertable = true, updatable = false, nullable = false)
protected Long id;
#Type(type="LocalDateTime")
#Column(name = "created", nullable = false, insertable = true, updatable = false)
protected LocalDateTime created;
#Type(type="LocalDateTime")
#Column(name = "refreshed", nullable = false, insertable = true, updatable = true)
protected LocalDateTime refreshed;
#PreUpdate
protected void onUpdate() {
refreshed = now();
}
#PrePersist
protected void onCreate() {
created = refreshed = now();
}
}
Here is an example "query", as said I am using hibernate criteria as well as HQL, the problem occurs with both methods.
session
.createCriteria(Item.class)
.add(eq("id", id))
.uniqueResult();
With standard JPA annotations it would look like this (updated):
#ManyToOne
#JoinColumns({
#JoinColumn(name="site", referencedColumnName="site", insertable = false, updatable = false),
#JoinColumn(name="primary_category_id", referencedColumnName="category_id", insertable = false, updatable = false)
})
private Category primaryCategory;
#ManyToOne
#JoinColumns({
#JoinColumn(name="site", referencedColumnName="site", insertable = false, updatable = false),
#JoinColumn(name="secondary_category_id", referencedColumnName="category_id", insertable = false, updatable = false)
})
private Category secondaryCategory;
UPDATE: I found that the second select statement is generated only when you use join by a composite key: Hibernate tries to resolve associations for {site=site, id=null} using TwoPhaseLoad. But if you write
#ManyToOne
#JoinColumn(name="secondary_category_id")
private Category secondaryCategory;
and secondary_category_id is null then the only one select statement will be generated, and the secondaryCategory value will be null. Maybe it will help you somehow. For example, you could add a constraint on site field while building your criteria:
Category c = (Category) session.createCriteria(Category.class)
.add(Restrictions.eq("id", 1L)) // for example
// here you define additional restriction on site field
.createAlias("secondaryCategory", "sc", JoinType.LEFT_OUTER_JOIN, Restrictions.sqlRestriction("this_.site = {alias}.site"))
.uniqueResult();
I did a quick test using your classes, and the following query code (using JPA criteria queries rather than native Hibernate)
CriteriaQuery<Item> cq = em.getCriteriaBuilder().createQuery(Item.class);
EntityGraph<Item> entityGraph = em.createEntityGraph(Item.class);
entityGraph.addSubgraph("primaryCategory", Category.class);
entityGraph.addSubgraph("secondaryCategory", Category.class);
List<Item> items = em.createQuery(cq.select(cq.from(Item.class)))
.setHint("javax.persistence.loadgraph", entityGraph)
.getResultList();
results in the following SQL being generated (formatted for readability):
select item0_.id as id1_1_0_,
category1_.id as id1_0_1_,
category2_.id as id1_0_2_,
item0_.site as site4_1_0_,
item0_.primary_category_id as primary_2_1_0_,
item0_.secondary_category_id as secondar3_1_0_,
category1_.category_id as category2_0_1_,
category1_.name as name3_0_1_,
category1_.site as site4_0_1_,
category2_.category_id as category2_0_2_,
category2_.name as name3_0_2_,
category2_.site as site4_0_2_
from item item0_
left outer join category category1_
on item0_.site=category1_.site
and item0_.secondary_category_id=category1_.category_id
left outer join category category2_
on item0_.site=category2_.site
and item0_.primary_category_id=category2_.category_id
As you can see, both category tables are being joined in the same SELECT
Try the following solution:
#Entity
#Table(name = "item", schema = "public", catalog = "stackoverflow_question")
#DynamicUpdate
public class Item {
#ManyToOne
#JoinColumn(name="site")
private Category primaryCategory;
#ManyToOne
#JoinColumn(name="site")
private Category secondaryCategory;
}
#Entity
#Table(name = "category", schema = "public", catalog = "stackoverflow_question")
public class Category {
#OneToMany(targetEntity=Item.class, mappedBy="primaryCategory", cascade=CascadeType.ALL)
private List<Item> primaryCategoryList;
#OneToMany(targetEntity=Item.class, mappedBy="secondaryCategory", cascade=CascadeType.ALL)
private List<Item> secondaryCategoryList;
}
I have the following classes laid out like so:
class User {
#Id
private long id;
#OneToMany(fetch = FetchType.EAGER,cascade = CascadeType.ALL)
Set<UserRole> userRoles;
}
class UserRole {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private int id;
#Column(name = "role", nullable = false, length = 45)
private String role;
}
I'm attempting to query for users that have a specific role (in this case, all users with the role ROLE_ADMIN), using the following query:
org.hibernate.query.Query<User> userQuery=session.createQuery("from User as mc where mc.userRoles in (from UserRole as ur where ur.role in (:uRoles))",User.class);
Set<String> roles = new HashSet<String>();
roles.add("ROLE_ADMIN");
userQuery.setParameterList("uRoles", roles);
List<User> admins = userQuery.getResultList();
However, the query is not returning any results.
session.createQuery(
"from User as user join user.userRoles as userRole where userRole.role in :roles")
.setParameter("roles", Arrays.asList("ROLE_ADMIN"))
.getResultList();
I have Test entity :
public class Test {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "duration", nullable = false)
private int duration;
#Column(name = "test_name", nullable = false, unique = true)
private String testName;
#Column(name = "archived", nullable = false)
private boolean archived;
#OneToMany(mappedBy = "test", fetch = FetchType.EAGER)
private Set<Question> questions;
#ManyToMany(mappedBy = "tests")
private Set<User> users;
Question Entity:
public class Question {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "is_multichoice", nullable = false)
private boolean isMultichoice;
#Column(name = "is_open", nullable = false)
private boolean isOpen;
#Column(name = "picture")
private String picture;
#Column(name = "question")
private String question;
#ManyToOne
#JoinColumn(name = "test_id", nullable = false)
private Test test;
#Column(name = "archived", nullable = false)
private boolean isArchived;
#OneToMany(mappedBy = "question", fetch = FetchType.EAGER)
private Set<Answer> answers;
This Test entity has Set of questions, in such way Question Entity has Set of answers.
I wrote SQL query to get test (The reason why it is not HQL you could find by link Hibernate HQL : no entity found for query) :
#NamedNativeQuery(name = "getCurrentTestById",
query = "SELECT t.id as tId, t.test_name, t.duration, q.id as qId, " +
"q.question as question, q.is_multichoice as is_multichoice, " +
"q.is_open as is_open, a.id as aId, a.answer_text as answer_text FROM result r " +
"JOIN test t ON r.test_id = t.id " +
"JOIN user u ON r.user_id = u.id " +
"JOIN question q ON t.id = q.test_id JOIN answer a ON q.id = a.question_id " +
"WHERE t.id = :testId AND u.id = :userId AND r.permission = :permissionId " +
"AND q.archived = false AND a.archived = false")
Now i need to map it to my entity Test by using #SqlResultSetMapping annotation:
#SqlResultSetMappings({
#SqlResultSetMapping(name="toTest",
entities = {
#EntityResult(entityClass = com.bionic.entities.Test.class, fields = {
#FieldResult(name = "id", column = "tId"),
#FieldResult(name = "test_name", column = "test_name"),
#FieldResult(name = "duration", column = "duration"),
#FieldResult(name = "questions.question", column = "question"),
#FieldResult(name = "questions.id", column = "qId"),
#FieldResult(name = "questions.isMultichoice", column = "is_multichoice"),
#FieldResult(name = "questions.isOpen", column = "is_open"),
#FieldResult(name = "questions.answers.id", column = "aId"),
#FieldResult(name = "questions.answers.answer_text", column = "answer_text"),
})
})
})
I am getting exception :
Caused by: org.hibernate.MappingException: dotted notation reference neither a component nor a many/one to one
This is why frameworks are generally bad news. Instead of using hibernate, you should follow the interface segregation principle. Your application should not know or care about How to select the data you need and what the table names are etc. Simply create a stored procedure that takes this responsibility and call it as opposed to having all the junk code in your app. Then if you want an easy way to map just have your stored proc return json by calling For JSON at the end. Mapping object fields to the JSON object becomes a piece of cake. You will find that with frameworks you spend more time troubleshooting the framework than actually programming.
I am struggling with Hibernate Criteria. My aim is to create the following request using Hibernate Criteria :
select
count(*) as y0_
from
PInterface this_
inner join
Product product2_
on this_.product_id=product2_.id
where
this_.product_interface_type_id=?
Here is my code:
#Entity #Table(name = "PInterface")
public class PInterface {
#Id
#GeneratedValue
#Column(name = "id", nullable = false, insertable = false, updatable = false)
private int id;
#Column(name = "product_id")
private int productId;
#Column(name = "product_interface_type_id")
private int type;
#ManyToOne(optional=false)
#JoinColumn(name = "product_id", referencedColumnName = "id", insertable=false, updatable=false)
private Product product;
}
#Entity #Table(name = "Product")
public class Product {
#Id
#GeneratedValue
#Column(name = "id", nullable = false, insertable = false, updatable = false)
private int id;
private String name;
}
//Criteria is :
Object criteria = sessionFactory.getCurrentSession()
.createCriteria(PInterface.class)
.add(Restrictions.eq("type", 1))
.setProjection(Projections.rowCount())
.uniqueResult()
;
However, the results ...
select
count(*) as y0_
from
PInterface this_
where
this_.product_interface_type_id=?
Where Inner join?
Thank you for help!
How about this:
Object criteria = sessionFactory.getCurrentSession()
.createCriteria(PInterface.class)
.createCriteria("product")
.createAlias("product", "p")
.add( Restrictions.eqProperty("p.id", "productId") )
.add(Restrictions.eq("type", 1))
.setProjection(Projections.rowCount())
.uniqueResult();