HQL query with several joins - java

I have the following relation of three classes:
#Entity
public class User{
#OnetoMany
List<Attribute> attributes = new ArrayList<Attribute>();
}
#Entity
public class Attribute{
#ManyToOne
AttributeType attributeType;
}
#Entity
public class AttributeType{
#Column
String type;
}
One user can have n attributes of m types.
I need to create HQL query which will return all Atribute Types List<AttributeType> of specific user attributes.
For example user has attribute a of type t, atribute b of type t and attribute c of type t1.
I need to return List<AttributeType> which will contain t and t1.
Please help. I just got lost in this query.

You shall map Attribute to User many to one relation, so the following query is what you need:
select distinct atr.attributeType
from Attribute atr
where atr.user = :user
I think the following query will work too:
select distinct atrs.attributeType
from User as user
join user.attributes as atrs
where user.id = :user_id

Related

Dynamic Query Instead of #subselect when giving an Entity data

I got the following entity:
#Entity
#Immutable
#Subselect("select distinct r.code, r.dsc\r\n"
+ "from roles r, accesses a\r\n"
+ "where r.code = '12'\r\n")
#MasterEntity(labelCode = "Scenario")
public class Scenario implements java.io.Serializable {
I want to use a dynamic query (or parameterized) instead of this static query.
for example: r.code should be equal to a parameter variable not "12"
is there a replacement for #Subselect while I use #Immutable?

JPA: Check if Collection has member with property

In my software, I have an entity (let's call it Member) with a collection of another entity (let's call it State). The query I need to write should return all members who have no State with a specific property value (e. g. 5).
Here are the relevant parts of the entities:
public class Member {
#JoinColumn(name = "MEMBER_ID")
#OneToMany
private List<State> states;
#Column
private String name;
}
public class State {
#Column
private int property;
}
Note that there is no bidirectional mapping between Member and State, the mapping is declared on the non-owning side of the relation (Member). In SQL I would create a query like this:
SELECT m.name
FROM Member m
WHERE NOT EXISTS (
SELECT *
FROM State s
WHERE
m.id = s.member_id
AND s.property = 5
);
But I don't know of any way to achieve the same thing in JPQL without having a mapping on the owning side of the relation. Is there any way to achieve this without having to bother with bidirectional mappings?
JPA allows to use collection references in subquery from clauses, so you can use this:
SELECT m.name
FROM Member m
WHERE NOT EXISTS(
SELECT 1
FROM m.states s
WHERE s.property = 5
)
This will produce exactly the SQL you want.
you can write native query like this
select name from Member where member_id not in ( select id from states
where property = 5)
Try something like this
select m.name from Member m where not exists(
from Member m1 join m1.states s where s.property = 5
)
or
select m.name from Member m where m.id not in(
select m1.id from Member m1 join m1.states s where s.property = 5
)

java and mybatis - misunderstanding one-to-many relation - only annotations

I have a two tables: Person and Dog. You know that person may have more than one dog.
My model is:
public class {
int personId;
List <Dog> dogs;
String name;
String surname;
}
public class Dog{
String name;
int dogId;
}
When it comes to database it is fairly similar:
PersonID(PK), Name (String), surname(String)
dogId(PK), name(String), IdOwner(FK)
Can you help me write select in mybatis ? I tried to read about #one and #many.
If you are using MyBatis you have two options described in the reference documentation:
Nested Select: By executing another mapped SQL statement that returns the complex type desired.
Nested Results: By using nested result mappings to deal with repeating subsets of joined results.
In your case, as you want to load the many association you must use the Nested Select, because you can't load a many association using a fetch outer join (just associations with one row fetched)
Nested Select
In this option you should need to add a reference to the select, which loads the daya by the foreign key relationship (in your case foreign key of person), of the relationship which in your case is dogs in the `ResultMap.
So you should have a query which loads the Person table:
<select id="findById" resultMap="personResult">
SELECT * FROM PERSON WHERE NAME = #{name}
</select>
Its method:
Person findById(String name);
Then a query which loads the dogs by person key relationship:
<select id="findDogsByPerson" resultType="Dog">
SELECT * FROM DOG WHERE ID_PERSON = #{namePerson}
</select>
And its method:
List<Dog> findDogsByPerson(String namePerson);
Then you must add the select as association in the resultmap referencing to the select by foreign key (findDogsByPerson). In your case is a many association, so you should use the collection tag instead of association.
<resultMap id="personResult" type="Person">
<!--Other properties maps -->
<!-- ..... -->
<collection property="dogs" column="id_person" javaType="Dog" select="selectDogByPerson"/>
<!-- ..... -->
</resultMap>
Annotation alternative
If you want you can use annotations to do it. It's almost the same but the ResultMap and Select goes above the methods. It would using the anotation #Many referencing to the many relationship.
#Select("SELECT * FROM PERSON WHERE NAME = #{name}")
    #Results(value = {
          #Result(property="name", column="name"),
          #Result(property="surname", column="surname"),
          #Result(property="dogs", javaType=List.class, column="name",
                             many=#Many(select="findDogsByPerson"))})
Person findById(String name);
#Select("SELECT * FROM DOG WHERE ID_PERSON = #{namePerson}")
#Results(value = {
          #Result(property="name", column="name"),
          #Result(property="dogId", column="dogId")})
List<Dog> findDogsByPerson(String namePerson);

Hibernate HQL Left Join Query

I have two tables which I need to be joined but there in no relation specified in the entity. Can I write something like
select uc.id, uc.name, mpn.name from UCR uc, MpnMapping mpn
I'm getting an error called Exception in thread "main" org.hibernate.hql.ast.QuerySyntaxException: unexpected token
Yes you can use new operator and a DTO class to set the values..
Query
select new com.example.UCRMNP(uc.id, uc.name, mpn.name) from UCR uc, MpnMapping mpn;
DTO class
First can create a DTO class and specify all the column variables, like this
class UCRMNP{
int id;
String name;
String name1;
public UCRMNP( int id, String name, String name1){
this.id=id;
this.name=name;
this.name1=name1;
}
}
Now you can set the retrieved data to that specific DTO class, You dont want to
annotate it with anything, just specify the constructor and execute
the Query using new operator.
Yes, you can do it by specifing the join in the where clause. It must be something like this:
select a, b from A a, B b where a.joinColumn = b.joinColumn
You can see more info in the below links:
Joining two unrelated tables in hibernate
http://www.codewrecks.com/blog/index.php/2009/09/04/theta-join-in-hql-join-with-unrelated-entities/

Hibernate/JPA: Is it possible to retrieve heterogeneous entities in a single query?

I have 2 entities: EntityA and EntityB.
They are unrelated, and I cannot put them in a Inheritance tree for some restrictions out of the scope of this question.
But I need to get in the same JPQL or HQL query a mixed List containing all the instances of both entities. Is this possible with JPA or even Hibernate directly?
I need somethign like this:
FROM EntityA WHERE fieldA=1
UNION
FROM EntityB WHERE fieldB="aa"
Any hint?
Well, I finally figured it out.
It is enought to make the entities implement a common interface (it is not even needed to declare this interface on Hibernate).
Then, a query like this can be done:
FROM my.package.CommonInterface obj
WHERE obj IN (FROM EntityA WHERE fieldA=1) OR
obj IN (FROM EntityB WHERE fieldB='a')
This way, you retrieve a List<CommonInterface>.
Problem solved.
Best thing is to performs two queries.
But if you must:
You can create a POJO to retrieve them:
class EntityAandEntityB {
EntityA a;
EntityB b;
long idA;
long idB;
int fieldA;
String fieldB;
public EntityAandEntityB(long idA, long IdB, int fieldA, String fieldB) {
this.a = new EntityA(idA, fieldA);
this.b = new EntityB(idB, fieldB);
}
}
Then your query would be:
select new package.EntityAandEntityB(a.idA, a.fieldA, b.idB, b.fieldB) from (
(select idA, fieldA from EntityA) a
UNION
(select idB, fieldB from EntityB) b)
This is dirty and you probably must to look carefully the syntax.
Regards.

Categories