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)
Related
I am using Spring Boot 2 with Hibernate and I have an entity named ItemCarga with this:
#ManyToMany(cascade = { CascadeType.DETACH }, fetch = FetchType.LAZY)
#JoinTable(name = "rel_transp_carga", joinColumns = { #JoinColumn(name = "fk_item_carga") }, inverseJoinColumns = { #JoinColumn(name = "fk_transportadora") })
#LazyCollection(LazyCollectionOption.TRUE)
private Set<Transportadora> transportadoras = new HashSet<Transportadora>();
Whey do a query using that entity on my repository, like this:
#Query("select e from ItemCarga e where e.cnpjCeramica = :cnpjCeramica and (e.dataInserido between :inicio and :fim) ")
List<ItemCarga> listarProdutosPorPeriodo(
#Param("cnpjCeramica") String cnpjCeramica,
#Param("inicio") Date dataInicial,
#Param("fim") Date dataFinal,
Sort sort);
The result is a set of ItemCarga entity with the attribute transportadoras fetched with all its items.
It shouldn't it be null or empty?
Shouldn't be ignored since I didn't mention that attribute on my select?
You did mention the attribute in the query: select e from ItemCarga e. This means you're fetching the whole ItemCarga entity. Since you defined transportadoras as fetch = FetchType.LAZY, a proxy is created (the data is not fetched from the database).
If you're invoking the query withing transaction, you can iterate over the set, then hibernate will fetch the child entities (this often leads to n+1 select problem). If you try to access it outside of transaction, LazyInitializationException will be thrown.
Since it's just a hint for hibernate, you can make sure, the Set won't be fetched in a couple of ways:
by not querying for it, for example:
#Query("select e.field1, e.field2 from ItemCarga e ...")
List<Object[]> listarProdutosPorPeriodo...
The downside is that you have to cast the results,
by using dto and query mapping. I won't describe it in detail, more you can find here,
by using projections - interfaces with getters and setters for the fields you want to fetch. More details here.
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.
Suppose I have some generic tables apple, orange etc and a table note which contains notes about a row in one of my generic table. The note is stored by saving the entity_type (e.g. the table name) and entity_id (e.g. the id of the row).
I'm trying to make a unidirectional One-to-Many mapping from apple to note. Effectively creating this relationship:
SELECT *
FROM apple f
INNER JOIN note n
ON f.id = n.entity_id
AND n.entity_type = 'apple'
I've been trying something like:
#Entity
public class Apple {
...
#OneToMany
#JoinColumn(name = "entity_id", referencedColumnName = "id")
#WhereJoinTable(clause = "entity_type = 'apple'")
private Set<Note> changeNotes = new HashSet<>();
Which isn't working (error is #WhereJoinTable on an association without join table). Any ideas?
Update:
I think this is the sort of thing I"m trying to do https://docs.oracle.com/html/E13946_02/ref_guide_mapping_notes_nonstdjoins.html
However hibernate is looking for a column instead of just using the string...
I have the following situation:
#Entity
public class Period
{
String Name;
}
#Entity
public class Bill
{
Period period;
#OneToMany(mappedBy = "bill", fetch = FetchType.LAZY)
private List<Entry> entry = new ArrayList<Entry>(0);
}
#Entity
public class Entry
{
#NotNull
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "BILL_ID", nullable = false)
Bill bill;
String text;
BigDecimal amount;
}
So what I need is to fetch all the data in a single query, either with the root being the Bill or the Entry using JPA 2.0 criteria (with Hibernate behind). I've read few posts about this problem HERE and HERE and it seems that I can't use subqueries in the result or fetch data two levels deep.
EDIT: To make my problem more clear: When I use Entry as root, I can't fetch Period and when I use Bill as root I can't fetch all other tables in Entry. Also I can't use eager fetch because there are other use cases that need those tables.
Are there any other ways to do this?
Thanks!
To fetch data from association, you use left join fetch clauses:
select distinct b from Bill b
left join fetch b.period
left join fetch b.entry
where b...
or
select distinct e from Entry e
left join fetch e.bill b
left join fetch b.period
where e...
Regarding Criteria, its fetch() method returns a Fetch, which itself has a method fetch() returning a Fetch(), which itself has a method fetch() returning a Fetch, etc. So yes, its supports as many levels you want.
Update: look my answer below on how to check if 2 list intersects (both for #ElementCollection with string/enums and usual entities list mapped like #OneToMany)
I have an entity which contains #ElementCollectionfield with enums.
public enum StatusType {
NEW, PENDING, CLOSED;
}
#Entity
public class MyEntity {
#ElementCollection
#CollectionTable(name = "status_type", joinColumns = {#JoinColumn(name = "my_entity_id")})
#Column(name = "status_type", nullable = false)
private Set<StatusType > statusTypes = new HashSet<StatusType >();
...
}
Now I want to get all entities which contains status NEW or PENDING (or both).
I'm trying to use this query:
SELECT DISTINCT u FROM MyEntity u WHERE u.statusTypes in :statusTypes
But I'm getting exception: org.postgresql.util.PSQLException: No value specified for parameter 9.
How to properly query on collections and filter by intersections?
Problem solved by adding JOIN clause to HQL. Hibernate couldn't implicitly recognize that query needs JOIN clause. May be it will help someone:
SELECT DISTINCT u FROM MyEntity u
LEFT JOIN u.statusTypes statusTypes
WHERE statusTypes in :statusTypes
I set the query params like this:
query.setParameter( "statusTypes", listOfStatusTypesEnums);
It will select rows where at least one element of listOfStatusTypesEnums list is present in entity's statusTypes property (i.e. if 2 list are intersects in some way).
If you have usual list of entities (which are not #ElementCollection, but #OneToMany etc), same rule will work as well. Just use like this: LEFT JOIN u.subEntities subEntities WHERE subEntities.id in :subEntityIds