I have 2 tables Asset and Asset_Dist_Types. Asset is parent and Asset_Dist_Types is a child table. Asset_Dist_Types is having 2 columns asset_id and lkp_dist_type where asset_id is the primary key in Asset table. In Asset_Dist_Types it is a many to many (one asset_id can have multiple lkp_dist_type entries.) In java, we have entity class only for Asset table. In that for Asset_Dist_Type, they have mentioned it as collection of elements. In Asset.java, entry for Asset_Dist_Type is as follows.
#CollectionOfElements
#JoinTable(name = "ASSET_DIST_TYPE", joinColumns = #JoinColumn(name="ASSET_ID"))
#Column(name="LKP_DIST_TYPE")
private Set<Integer> distTypes = new LinkedHashSet<Integer>(0);
Now I would like to update Asset_Dist_Type table's lkp_dist_type column. I have list of asset id's. I have written following query to update it.
int hql = entityManager.createQuery(
"update Asset a set a.distTypes = :distTypeParamId where a.assetId in (:assetIdParam)")
.setParameter("distTypeParamId", distTypeList)
.setParameter("assetIdParam", assetIdListToUpdateLOB)
.executeUpdate();
But this is throwing
javax.persistence.PersistenceException:
org.hibernate.exception.GenericJDBCException: could not execute update query.
Since I am new to hibernate I am not getting what is the solution. Can someone please help me?
Solved it by following a different way.. I got list of asset id's and list of distribution types. I iterated over the list of asset id's and for each asset id I added list of distribution types and flushed it. It is working now..!
After getting list of asset id's
for(int i=0;i<assetIdListToUpdateLOB.size();i++){
int assetId = assetIdListToUpdateLOB.get(i);
System.out.println(assetId);
List<Asset> assetDetailsList = entityManager
.createQuery(
"select distinct asset from Asset asset "
+ "left join fetch asset.distTypes dt "
+ "where asset.assetId = :assetIdParam")
.setParameter("assetIdParam", assetId).getResultList();
if(assetDetailsList.size()>0){
this.asset = assetDetailsList.get(0);
asset.getDistTypes().clear();
asset.getDistTypes().addAll(selectedDistributionTypes);
entityManager.flush();
}
}
Related
I have three Hibernate Entities:
CoverArt
Song
Song represent a song file (e.g mp3 file),
CoverArt contains songs coverart, a song can have multiple pieces of coverart
Within Song I define link to CoverArt as:
#OneToMany(fetch=FetchType.LAZY, cascade={CascadeType.ALL})
#JoinColumn(name = "recNo")
private List<CoverArt> coverArts;
Within CoverArt there is no link defined to Song, we just have
#Id
#GeneratedValue
private Integer id;
The application works okay, except when I want to empty the Song and CoverArt entities.
It doesn't happen consistently but if I try and delete from Song first
e.g
String hql = String.format("delete from CoverArt");
Query query = session.createQuery(hql);
query.executeUpdate();
hql = String.format("delete from Song");
query = session.createQuery(hql);
query.executeUpdate();
session.getTransaction().commit();
I get exception:
Caused by: org.h2.jdbc.JdbcSQLException: Referential integrity
constraint violation: "FK_CBUK1UQ1D0DQAA077XH16SRX2:
PUBLIC.SONG_COVERART FOREIGN KEY(COVERARTS_ID) REFERENCES
PUBLIC.COVERART(ID) (13)"; SQL statement:
and if I try the other way
String hql = String.format("delete from Song");
Query query = session.createQuery(hql);
query.executeUpdate();
hql = String.format("delete from CoverArt");
query = session.createQuery(hql);
query.executeUpdate();
I get exception
Caused by: org.h2.jdbc.JdbcSQLException: Referential integrity
constraint violation: "FK_4B4O39V3RSF1IWWRIX6QQQTLK:
PUBLIC.SONG_COVERART FOREIGN KEY(SONG_RECNO) REFERENCES
PUBLIC.SONG(RECNO) (1)"; SQL statement:
So its impossible to empty the tables, CoverArt entity only exists as part of a Song so I assumed their would only be a Foreign Key from a COVER_ART table to SONG table and expected I could delete everything from CoverArt without a problem, but there is an interim table created SONG_COVERART that has foreign keys to both tables preventing deletion.
What am I doing wrong (using Hibernate 4.3.11)
Probably because in a previous version of your code didn't have the JoinColumn annotation, and Hibernate thus created a join table for this association, that you filled, but forgot to delete.
I need to select products based on tags, here are the tables
products: productId, name, description, price, etc
tags: tagId, name
product_tags: productId, tagId
and I have 2 classes Product and Tag and relation is specified in Product class
#OneToMany(cascade = CascadeType.DETACH)
#JoinTable(
name = "product_tags",
joinColumns = #JoinColumn(name = "productId"),
inverseJoinColumns = #JoinColumn(name = "tagId")
)
public List getTags() {
return tags;
}
public void setTags(List tags) {
this.tags = tags;
}
Please note I only want to select products and not tags. following works fine
Criteria cri = getSession().createCriteria(Product.class);
cri.setFirstResult(index);
cri.setMaxResults(limit);
return cri.list();
As I am trying to get list for pagination, so I need total number of pages that can be retrieved by getting totalRecords/recordPerPage
Criteria cri = getSession().createCriteria(Product.class);
//add any required filter to criteria
//e.g cri.add(Restrictions.like("name", keyword, MatchMode.ANYWHERE));
//********** Following code is in utility function ******************/
//Get total number of records matching criteria
cri.setProjection(Projections.rowCount());
Long totalRecords = (Long)cri.uniqueResult();
//Get paginated records
cri.setProjection(null);// This is evil but works
cri.setFirstResult(index);
cri.setMaxResults(limit);
paginatedRecords = cri.list();
Question 1: Is it possible to set some thing like cri.setProjection(Product.class) instead of setting it null, I am aware that I can create a projection list and add all the column of product class but that seems overkill + the common part is in utility function and I found no way to retrieve the previous projection. cri.getProject()
Why I need another method because cri.setProjection(null) fails when I apply join, because it will project all the column of products, tags, product_tags. which cannot be casted to List
Get all products that have associated tag ids as (4,5,6)
cri.createAlias("tags", "t");
cri.add(Restrictions.in("t.tagId", new Integer[]{4,5,6}));
Here is the issued query
select
this_.productId as productId1_9_1_,
this_.categoryId as category6_9_1_,
this_.description as descript8_9_1_,
this_.name as name13_9_1_,
tags3_.productId as productId1_9_,
t1_.tagId as tagId2_10_,
t1_.tagId as tagId1_11_0_,
t1_.name as name4_11_0_,
from
products this_
inner join
product_tags tags3_
on this_.productId=tags3_.productId
inner join
tags t1_
on tags3_.tagId=t1_.tagId
where t1_.tagId in (4,5,6) limit 25
I have found a work-around for this as follows
cri.setProjection(null)
criteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY)
This will fix type cast exception.
Question 2: The back-end query is still the same, it join and project all the columns of all involved tables. ((Yakkh dirty)), Why the same query?, I am expecting projections on Product class only
I have performance problems with the group by feature in Hibernate. Consider this 2 classes:
public class Project
{
...
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name="user")
private User user;
...
}
public class User
{
...
private Integer id;
private String name;
...
}
Now I try to get a list of all Users assigned to the project. But this query is uselessly slow (more than 100'000 project entries, a lot of joins):
Session session = this.sessionFactory.openSession();
String SQL="SELECT user.id as id, user.name as name FROM Project p GROUP BY p.user.id";
Query q = session.createQuery(SQL);
q.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
List<Object> list = q.list();
session.close();
I try to change the query this way, but this is not working either because the variable user is an Object (but this would work as a native SQL query):
SELECT id, name FROM User WHERE id IN(SELECT user FROM Project GROUP BY user)
Any other ideas? Thank you in advance!
Try creating an index from the foreign key column.
#javax.persistence.Table(name = "project")
#Table(appliesTo = "project" ,indexes = #Index(columnNames = "user", name = "user_index"))
#Entity
public class Project
{
..
Update
columnNames has been depricated. Use columnList instead.
#Index(columnList = "user", name = "user_index")
Hope this helps.
I doubt this has to do with Hibernate being slow. Most probably the SQL query is slow if run directly on the database as well.
One good practice is to create indices whenever you have a foreign key in your table. In your case create an index for user_id on your project table and run the query once more.
If you want to get all users assigned to the project you don't need group by. Do something like this
select user from Project project inner join project.user user where project.id = :projectId
Hibernate / Java newbie here, any help will be greatly appreciated!
So...... I have a table called ITEMS and a ITEM_OWNER_JOIN table joined by the
"itemKey" column and the "owners" column which is a Set of String values...
In Item.java I have:
#ForeignKey(name="FK_ITEM_OWNER_FK")
#ElementCollection(targetClass=java.lang.String.class, fetch = FetchType.Eager)
#JoinTable(name= "ITEM_OWNER_JOIN", joinColumns=#JoinColumn(name="itemKey"))
private Set<String> owners = new HashSet<String>();
and basically I'm trying to run a HQL querying for results where the owners match a
searchText param....
so I've tried:
Query q = session.createQuery("select distinct i.itemKey from Item i inner join"+
" i.owners o where o.owners like '"+searchText+"'");
and I am getting a org.hibernate.QueryException: cannot dereference scalar collection element: owners [select distinct w.workspaceKey from.....]
I've tried researching for that exception to no avail... :(
Thank you for your time!
Something as below
HQL
select i
from Item i
inner join i.owners io
where io like 'searchText';
Oracle Query
SELECT Distinct(i.itemKey)
FROM Item i, ITEM_OWNER_JOIN io
WHERE i.itemKey = io.itemKey and io.x like '%%';
where 'x' is column name.
Working example from my application
From entity:
#ElementCollection
#JoinTable(name = "rule_tagged_name", joinColumns = #JoinColumn(name = "re_rule", referencedColumnName = "id"))
private List<String> ruleTagNames;
DB Columns
RE_RULE NUMBER
RULE_TAG_NAMES
HQL
Select ru FROM Rule ru inner join ru.ruleTagNames rt_name WHERE rt_name in :tagNameList
Try using with IN operator as owners is multiple.
Query hqlQuery = session.createQuery("select distinct i.itemKey from Item i inner join"+
" i.owners o where o.owners in :ownersParam");
Then set parameter owners with the owner set value,
Set<String> ownerSet = new HashSet<String>();
ownerSet.add(searchText);
hqlQuery.setParameterList("ownersParam", ownerSet);
//then retrieve result
I have a mapped entity with a property "latestHistory", which is mapped through a join table, like:
class Record {
#OneToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE }, fetch = FetchType.LAZY, optional = true)
#JoinTable(name = "latest_history_join_view", joinColumns = { #JoinColumn(name = "record_id") }, inverseJoinColumns = { #JoinColumn(name = "history_id") })
#AccessType("field")
public History getLatestHistory() { ... }
}
The mapping works correctly when I call myRecord.getLatestHistory().
I have a complex native SQL query, which returns a batch of Records, and joins on the History for each record using the join table. I want to return Record entites from the query, and have the History objects populated in the result. My attempt looks like this:
StringBuffer sb = new StringBuffer();
sb.append("select {r.*}, {latestHistory.*}");
sb.append(" from record r");
sb.append(" left join latest_history_join_view lh on lh.record_id = r.record_id");
sb.append(" left join history latestHistory on latestHistory.history_id = lh.history_id");
SQLQuery query = session.createSQLQuery(sb.toString());
query.addEntity("r", Record.class).addJoin("latestHistory", "r.latestHistory");
When I do this, it generates a query like:
select
r.record_id, r.name...,
r_1.history_id, --this part is wrong; there is no such alias r_1
latestHistory.history_id, latestHistory.update_date, ...
from record r
left join latest_history_join_view lh on lh.record_id = r.record_id
left join history latestHistory on latestHistory.history_id = lh.history_id
How can I get it to join correctly and fetch my association, without messing up the select list?
[Update: some of the approaches that I've tried:
select {r.*}, {latestHistory.*} -> SQL error, generates a wrong column name "r_1.history_id"
select {r.*}, {anyOtherEntityAssociatedToR.*} -> wrong column name (as above)
select {r.*}, {r.history_id}, {latestHistory.*} -> hibernate error, r has no history_id column
select r.*, lh.history_id as history_id -> this works (though hackish), but doesn't accomplish the join
select r.*, lh.history_id as history_id, latestHistory.* -> appears correct, but results in column name collisions
select r.*, {latestHistory.*} -> error when hibernate looks for a nonexistent column in the result set (this happens if there is any alias at all in the select list)
It doesn't seem to make a lot of difference whether I use addEntity(...) or addJoin(...), as long as the leftmost (root) entity is added using addEntity.
]
I'm thinking you actually need to specify full path for your latestHistory in select e.g.
select {r.*}, {r.latestHistory.*}
otherwise Hibernate gets confused and attempts to treat it as a separate entity. The other option is to not specify injected aliases in select at all which should work for a single "to-one" relationship so long as column order in your tables matches property order in your entities.
I've never tried this on #OneToOne over association table, though.