I'm a little curious, is there a way to get result of connect by sql query like root Entity with already mapped descendants.
So if I'm insert in base something like this:
insert into table test (id, parent_id, some_text) values
(1, null, 'a'),
(2, 1, 'b'),
(3, 1, 'c'),
(4, 2, 'd');
then by sql query
select *
from test t
start with t.id = 1
connect by prior t.id = t.parent_id
order siblings by t.some_text
I will get
id | parent_id | some_text
1 null a
2 1 b
4 2 d
3 1 c
and by entity
#Entity
#Table(name = "test")
public class Test {
#Id
#Column(name = "id")
#GeneratedValue(generator = "increment")
#GenericGenerator(name = "increment", strategy = "increment")
private BigInteger id;
#Column(name = "parent_id")
private BigInteger parent_id;
#Column(name = "some_text")
private String someText;
#OneToMany(mappedBy = "parent")
private Set<Test> descendants;
#ManyToOne
#JoinColumn(name = "parent_id")
private Test parent;
// getters and setters
}
it will back to me as list of Test. It possible to get root and full tree by recursive function, but it will get new query on iteration (it will very long if I have a big tree).
So is there a possible good way to get root of this tree with already mapped descendants by this query (maybe extend/implement some class/interface which will process mapping from jdbc to entity)?
you can use CONNECT_BY_ROOT unary operator.
See docs
select t.*, connect_by_root id
from test t
start with t.id = 1
connect by prior t.id = t.parent_id
order siblings by t.some_text
BTW: this has nothing to do with Hibernace. This is purely Oracle specific solution.
Related
I'm trying to get a list of property policy_type_id from ListAttribute<Article, PolicyType>, but I can't figure out how to do it.
I come up with an inefficient method was select whole Collection of PolicyType then filter it later
Root<ArticleVersion> a = cq.from(ArticleVersion.class);
Join<ArticleVersion, Article> join1 = a.join(ArticleVersion_.article, JoinType.INNER);
cq.where(getCondition(cb, join1));
cq.multiselect(join1.get(Article_.article_id), join1.get(Article_.policyTypes), a);
Sadly, hibernate generate an error query like this
select article1_.article_id as col_0_0_, . as col_1_0_, articlever0_.article_version_id as col_2_0_ . As you can see, there is a . in select that make query broken (which I believe select all)
#Entity
#Table(name = "PolicyType", schema = "SM_Request")
#Getter
#Setter
#NoArgsConstructor
public class PolicyType {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int policy_type_id;
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinTable(name = "PolicyTypeArticle", schema = "SM_Request",
joinColumns = #JoinColumn(name = "policy_type_id"), inverseJoinColumns = #JoinColumn(name = "article_id"))
#JsonIgnore
private List<Article> articles;
}
After long searching, I think that hibernate doesn't support query tuple of primitive types and list of objects (which is kinda sad, compare to LINQ to query). I decided to break down my query into smaller parts. First, I select tuples of article_id and ArticleVersion. After that, I select a list of PolicyType which also contains article_id, and union 2 lists back.
By the time I wrote this, I have an idea that I could select all 3 joins together and transform data the way I want. But It really depend on many aspects, like how many join or which type of join you're using, how fast data in each table grown (JOIN queries vs multiple queries)
I am trying to fetch data of employee availability creating a query. I have used #ElementCollection annotation to map skills and daysAvailable, which stores data into other table.
TypedQuery<Employee> query = entityManager.createQuery("select e from Employee e where :day MEMBER OF e.daysAvailable and :list MEMBER OF e.skills ", Employee.class);//
query.setParameter("day", dayOfWeek);
query.setParameter("list", employeeRequestDTO.getSkills());
List<Employee> list = query.getResultList();
I am trying to pass a set in my query. If there is only one element in set then the query works but if more then 1, then it is not able to fetch. I have tried using e.skills in (:list) instead of
:list MEMBER OF e.skills. But still no luck!!
#Entity
public class Employee {
#Id
#GeneratedValue
private long id;
#Nationalized
private String name;
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(name = "skills", joinColumns = #JoinColumn(name = "emp_id"))
#Enumerated(EnumType.STRING)
private Set<EmployeeSkill> skills;
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(name = "days", joinColumns = #JoinColumn(name = "emp_id"))
#Enumerated(EnumType.STRING)
private Set<DayOfWeek> daysAvailable;
// Getters & Setters
This is the domain i have created and now want to fetch all employees who are available on a particular day and have particular skills. I have created query for this but it is showing error - java.sql.SQLException: Operand should contain 2 column(s)
This is the query generated-
select * from employee e where ( 'TUESDAY' in ( select d.days_available from days d where e.id=d.emp_id)) and (( 'PETTING','FEEDING' ) in (select s.skills from skills s where e.id=s.emp_id));
Any suggestions?
In JPQL, MEMBER OF takes a single argument and checks if that's contained in the provided collection.
Check out the Hibernate User Guide for more details.
Try this query instead:
select e
from Employee e
join e.skills s
where
:day MEMBER OF e.daysAvailable and
s in :list
I have 4 tables in relations. A,B,C,D.
So I wrote select bellow:
select NEW org.example.ExtendsA(a,b.name,c.name,d.name)
from A a LEFT JOIN a.bItems b LEFT JOIN a.cItems c LEFT JOIN b.dItems d
order by b.name ASC;
A is unique but the relations are incomplette.
and I tried this:
select NEW org.example.ExtendsA(a,b.name,c.name,d.name)
from A a LEFT JOIN FETCH a.bItems b LEFT JOIN FETCH a.cItems c
LEFT JOIN FETCH b.dItems d order by b.name ASC;
A is not unique.
A object definition is:
#Entity
public class A implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private Long id;
#NotNull
#Size(min = 1, max = 100)
#Column(name = "NAME")
private String name;
#OneToMany(mappedBy = "aId")
private List<B> bItems;
#OneToMany(mappedBy = "aId")
private List<C> cItems;
}
Some relations are empty but need A object with null relations.
Some A object has more than one relations between B and C and I want to select with all in one A object (distinct A).
Would you help me how to solve this issue? Maybe the approach is bad?
I use EclipeLink data provider.
This is a typical problem with loading OneToMany relathionships.
This is because of the nature of SQL result sets. Imagine a SQL result of a join of entity with it's other entities linked to it. On the left side, fields of this entity will be duplicated as many times as many related entities it has.
Unforunately, EclipseLink doesn't filter them out and you get many items of the same entity in your result. Although, EclipseLink is smart enough and each item will actually be the same Java object instance.
It's also the reason why you can't use setMaxResults in such queries.
You need to use distinct keyword that in this particular keys will not be mapped to a real SQL distinct, but will filter duplicated entities. Or, you can filter them manually.
I have a database table Communications with type, value and a foreign key as index that maps back to a Person table declared as follows:
#Table(name = 'communication', schema = 'schema')
#org.hibernate.annotations.Table(appliesTo = 'communication', indexes = {
#Index(name = "idx_communication_person_id", columnNames = { "person_id" })
}
)
And the Person object maps to this as:
#OneToMany(fetch = LAZY, cascade = ALL, orphanRemoval = true)
#JoinColumn(name = "person_id")
#OrderColumn
#Index(name = "idx_communication_person_id")
private final List<Communication> communications
Now I want to create a HQL query with Hibernate, that selects based on this index colum, like:
WHERE person.id in ( SELECT c.person_id FROM Communication c WHERE c.type = 3 AND c.value = 'john.doe#server.com' )
That doesn't work, because HQL doesn't know c.person_id at this point, because index columns are in general unknown to HQL.
How do I properly address the index in HQL, or if that is not possible: how do I write the statement to archive the same as the native-like query above?
EDIT: For performance reasons there must not be a JOIN in any form.
I think you need something like this:
SELECT p.* FROM person p
JOIN p.communication c
WHERE c.type = 3 AND c.value = 'john.doe#server.com'
That doesn't work, because HQL doesn't know c.person_id at this point, because index columns are in general unknown to HQL.
This doesn't make much sense to me.
If you want to have an HQL statement that returns a list of identifiers for Person based on some criteria, you can easily do it much like how your SQL statement is written.
SELECT p.id
FROM Communication c JOIN FETCH c.person p
WHERE c.type = :communicationType
AND c.value = :emailAddress
If you actually want persons, just write the query to select c.person rather than p.id in order to hydrate all Persons. In the following, the query allows you to specify a person identifier on the predicate if needed.
SELECT c.person
FROM Communication c JOIN FETCH c.person p
WHERE c.person.id = :personId
AND c.type = :communicationType
AND c.value = :emailAddress
UPDATE
If you don't want to use any joins, then simply expose the personId as a numeric value on your Communication entity without any association mappings.
public class Communication {
#Column(name = "personId", nullable = false, insertable = false, updatable = false)
private Long personId;
}
You should then be able to issue a query such as:
SELECT c.personId
FROM Communcation c
WHERE c.type = :communicationType
AND c.value = :emailAddress
I have two entities, Group and GroupMember. Group is like it sounds a group that has name and some other properties. Members of the group are mapped with GroupMember entity, which has an entry with a User and a Group for every group the user is member of. They look like the following:
#Entity
#Table(name = EntityTokens.GROUP_TABLE)
public class Group
{
#Id
#Column(name = EntityTokens.GROUP_ID_COLUMN)
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long groupId;
...
// Group members
#OneToMany(orphanRemoval = true, fetch = FetchType.LAZY, mappedBy = "group", cascade = {CascadeType.ALL})
private Collection<GroupMember> groupMembers;
}
#Entity
#Table(name = EntityTokens.GROUP_MEMBER_TABLE)
public class GroupMember
{
#Id
#Column(name = EntityTokens.GROUP_MEMBER_ID_COLUMN)
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long memberId;
...
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = EntityTokens.GROUP_MEMBER_ID_COLUMN)
private Group group;
}
I'm trying to write a criteria query that returns all groups that have some predefined properties and that the current user is not part of. My query looks like this:
CriteriaQuery<Group> q = cb.createQuery(Group.class);
Root<Group> root = q.from(Group.class);
Join<Group, GroupMember> groups = root.join(Group_.groupMembers);
q.select(root);
q.where(cb.notEqual(groups.get(GroupMember_.user), user),
cb.equal(root.get(Group_.global), false),
cb.equal(root.get(Group_.personal), false),
cb.equal(root.get(Group_.privacy), GroupPrivacy.PUBLIC));
q.distinct(true);
The user here represents the current user. This query doesn't work because if there are other members that are part of the same group as me they will be included in the query result due to the join. How should the correct query look like? I'm not that familiar with the criteria query API yet.
join for a ToMany relationship is conceptually an "anyOf" operation, meaning if any of the many is true then the expression is true.
What you want is an "allOf", criteria does not have this, you need to use a sub select for this in SQL.
The JPQL would be,
Select g from Group g where not exists (select m from g.members m where m.user = :user)
The criteria would be the same, using a sub criteria query for the exists.