Two entity classes:
#Entity
public class FilesInfo {
#Id
#GeneratedValue
private Integer id;
private String name;
private String url;
#OneToMany(cascade= CascadeType.ALL)
#JoinColumn(name="fileId")
private Collection<FilesShare> filesShared = new ArrayList<FilesShare>();
public Collection<FilesShare> getFilesShared() {
return filesShared;
}
public void setFilesShared(Collection<FilesShare> filesShared) {
this.filesShared = filesShared;
}
the second:
#Entity
public class FilesShare {
#Id
#GeneratedValue
private Integer id;
#Column(name="fileId")
private Integer fileId;
private int userId;
private int owner;
#ManyToOne
#JoinColumn(name="fileId", updatable=false,insertable=false)
private FilesInfo filesInfo;
public FilesInfo getFilesInfo() {
return filesInfo;
}
public void setFilesInfo(FilesInfo filesInfo) {
this.filesInfo = filesInfo;
}
the daoimpl mmethod:
public List<FilesInfo> reqSharedFiles(FilesShare fs) {
session=HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
List<FilesInfo> filesInfo = null;
filesInfo=(List<FilesInfo>)session.createQuery("from FilesInfo a, FilesShare b where a.id=b.fileId and b.userId=5 and b.owner=1").list();
now i dont understand when hibernate is mapping and returning the object by i am getting this error in action that it cant be casted :
Ljava.lang.Object; cannot be cast to app.domain.FilesInfo
The action
private List<FilesInfo> furls= new ArrayList<FilesInfo>();
furls=upload.reqSharedFiles(fs);
for(FilesInfo s: furls) // ERROR IS SHOWING HERE
{
System.out.println(s.getUrl());
}
Your query does not return a list of FilesInfo, but a list of two-element object arrays where the objects are of type FilesInfo and FilesShare.
You could either rewrite your query so that it only returns a FilesInfo, or attach a ResultTransformer that pulls out the part you're interested in or constructs an object that you can use to get the info you really want.
Your query can result in two diffrent objects, from FilesInfo a, FilesShare b so if it is a FileShare object it cannot be cast to a FilesInfo
see hql from
Thankyou all. Here is what i did after some search.
private List<Object[]> turls=new ArrayList<Object[]>(); //get the list of Object[] from HQL
for(Object[] r : turls)
{
FilesInfo inf =(FilesInfo)r[0];
System.out.println(inf.getUrl());
}
Related
I have following entity with its persistent collection
#Entity
#Table(name = "A")
public class A implements Identifiable<Long> {
#Id
private Long id;
#ElementCollection
#CollectionTable(name = "B", joinColumns = { #JoinColumn(name = "B_ID") })
private Collection<B> bList;
#ElementCollection
#CollectionTable(name = "C", joinColumns = { #JoinColumn(name = "C_ID") })
private Collection<C> cList;
}
After loading 10k rows A entities, I want to load its collection as well
// loading A entities
final List<A> aList = getA();
// looping from 10k results
for (final A a : aList) {
final List<B> bList = a.getB();
final List<C> cList = a.getC();
}
And select statement generated quite a lot (~10k).
Very poor performance here!
Any idea to work with batch select here?
I have solved this!
IDEA
Hibernate will take care of the sql statement and mapping to entity list value when using #ElementCollection. That’s comfortable to use but we have a trade off.
The more parent results we have, the worse performance we got. If we have 10k records parent, Hibernate will do selecting 10k times to fetch its children relation.
Instead of loading children for every single parent. Create native query to load everything.
we got the results like this:
PARENT_ID CHILD_ID
1 1
1 2
1 3
2 1
2 2
3 3
then implementing Hibernate transformer to convert these raw database objects to DTO.
Code example.
Create DTO
public class ADto {
private long id;
private Collection<BDto> bList = new HashSet<>();
// Constructor
public void addChildren(BDto b) {
bList.add(b);
}
//equals and hascode
}
public class BDto {
private long id;
// Constructor
//equals and hascode
}
And transformer
public class CustomTransformer extends AliasedTupleSubsetResultTransformer {
private final Map<Long, ADto> result = new HashMap<>();
private final Map<String, Integer> aliasIndexes = new HashMap<>();
#Override
public List transformList(final List list) {
return new ArrayList(new LinkedHashSet(list));
}
#Override
public UsableCapacity transformTuple(final Object[] tuple, final String[] aliases) {
init(aliases);
final A aEntity = (A) get(tuple, "parent"); // same as alias in DAO layer
final B bEntity = (B) get(tuple, "child"); // same as alias in DAO layer
final Long id = aEntity.getId();
final ADto aDto;
if (result.containsKey(id)) {
aDto = result.get(id);
} else {
aDto = new ADto(...);
}
aDto.addChildren(new BDto(...)); // create BDto instance from BEntity
result.put(id, aDto);
return aDto;
}
private Object get(final Object[] capacities, final String alias) {
return capacities[aliasIndexes.get(alias)];
}
private void init(final String[] aliases) {
if (aliasIndexes.isEmpty()) {
for (int i = 0; i < aliases.length; i++) {
final String alias = aliases[i];
aliasIndexes.put(alias, i);
}
}
}
}
DAO layer
final String queryString = "SELECT {parent.*}, {child.*} FROM A parent LEFT JOIN B child ON parent.id = child.parent_id";
final NativeQuery query = getCurrentSession().createNativeQuery(queryString)
.addEntity("parent", A.class)
.addEntity("child", B.class);
// Todo
query.setResultTransformer(new CustomTransformer());
return safeList(query);
I have a list of string in my DTO, i want to map it into a list of object, in the mapper i used the service to get the object by this string, but i have the below error
Can't map property "java.util.List<java.lang.String> customers" to
"java.util.List<com.softilys.soyouz.domain.Customer> customers".
Consider to declare/implement a mapping method:
"java.util.List<com.softilys.soyouz.domain.Customer>
map(java.util.List<java.lang.String> value)".
public class FirstDomain implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private String id;
private String description;
private List<Customer> customers;
}
public class FirstDomainDTO {
private String id;
private String description;
private List<String> customers;
}
#Mapper(uses = { CustomerService.class })
public interface FirstDomainMapper extends EntityMapper<FirstDomainDTO, FirstDomain> {
#Mapping(source = "customers", target = "customers")
FirstDomainDTO toDto(FirstDomain firstDomain);
#Mapping(source = "customers", target = "customers")
FirstDomain toEntity(FirstDomainDTO firstDomainDTO);
default String fromCustomer(Customer customer) {
return customer == null ? null : customer.getCode();
}
}
The error message you are getting should be enough to help you understand what the problem is. In this case MapStruct doesn't know how to map from List<String> into List<Customer>. The other way around is OK since you have defined
default String fromCustomer(Customer customer) {
return customer == null ? null : customer.getCode();
}
To fix this you need to defined the reverse as well.
#Mapper(uses = { CustomerService.class })
public interface FirstDomainMapper extends EntityMapper<FirstDomainDTO, FirstDomain> {
#Mapping(source = "customers", target = "customers")
FirstDomainDTO toDto(FirstDomain firstDomain);
#Mapping(source = "customers", target = "customers")
FirstDomain toEntity(FirstDomainDTO firstDomainDTO);
default String fromCustomer(Customer customer) {
return customer == null ? null : customer.getCode();
}
default Customer fromStringToCustomer(String customerId) {
// Implement your custom mapping logic here
}
}
I have problem, and I don't know how to solve it.
I have entity:
#Entity
#Table(name = "entity_languagetree")
#AttributeOverride(name = "id", column = #Column(name = "languagetree_id"))
public class LanguageTree extends BaseObject {
#ElementCollection(targetClass = java.lang.String.class, fetch = FetchType.EAGER)
#CollectionTable(name = "view_languagetree_to_stringlist")
private List<String> relationship = new ArrayList<>();
public LanguageTree() {
//
}
public List<String> getRelationship() {
return relationship;
}
public void setRelationship(List<String> relationship) {
this.relationship = relationship;
}
}
where BaseObject is
#MappedSuperclass
public class BaseObject {
#Id
#GeneratedValue
#Column(name = "entity_id")
private Long id;
/**
*
* #return true if the entity hasn't been persisted yet
*/
#Transient
public boolean isNew() {
return id == null;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Bean getBean() {
return null;
}
}
Work with object - in my servlet, I am calling jsVarTree() like this:
String var = jsVarTree();
My problem is, that after method jsVarTree is finished, hibernate delete my relationship list from entity LanguageTree. I don't know why! I am not calling any delete and etc.. (I AM SURE, I SPENT A LOT OF TIME IN DEBUGER!)
:
#Override
public String jsVarTree() {
TreeBuilder tb = new TreeBuilder(getLanguageList());
return tb.getJsVarString(); // THIS METHOD IS ONLY GETTER !!!!
}
#Override
public List<String> getLanguageList() {
LanguageTree lt = getLanguageTreeObject();
return lt.getRelationship();
}
#Override
public LanguageTree getLanguageTreeObject() {
long fakingId = languageTreeDao.getLastId();
ServerLogger.logDebug("LAST FAKING ID: " +fakingId);
return languageTreeDao.findOne(fakingId);
}
I found this log in loggor:
HibernateLog --> 15:01:03 DEBUG org.hibernate.SQL - delete from
view_languagetree_to_stringlist where LanguageTree_languagetree_id=?
Can somebody tell me, why hibernate call delete over my table?
I saw a table in phpmyadmin..
TABLE IS FULL.
String var = jsVarTree();
TABLE IS EMPTY.
Table is deleted after return tb.getJsVarString(); is finished.
Thank you for any help!
So I keep coming up short on this, and just can't seem to get it to work right.
Things seem to work fine when I use my HibernateUtil.get(clazz, pkId) method, but when I try using the HibernateUtil.pagedQuery(clazz, criterion, start, stop) I get multiple identical objects returned.
For example if there were 3 employees assigned to Role 1, then running...
Role role = HibernateUtil.get(Role.class, new Integer(1));
... works as expected. However, if I run...
List<Criterion> c = new ArrayList();
c.add(Restrictions.eq("roleTypeSeqNo", new Integer(1)));
List<Role> roles = (List<Role>) phi.util.hibernate.HibernateUtil.pagedQuery(Role.class, c, 0, 50);
... returns a List of 3 identical roles. All of which represent Role 1.
If someone could guide me down the right path, I would really appreciate it.
Thanks in advance!
Here's an abbreviated version of my classes
#Entity
#Table(name="ASSIGNMENTS")
public class Assignment implements Serializable {
#EmbeddedId
private AssignmentPK pk;
// After coming across many errors I finally caved and reverted roleTypeSeqNo back to just an Integer.
private Integer roleTypeSeqNo;
private String status;
private String location;
}
#Embeddable
public class AssignmentPK implements Serializable {
#ManyToOne
#JoinColumn(name="EMPLID")
private Employee employee;
#Column(name="PRIORITY_NO")
private String priorityNo;
}
#Entity
public class Employee implements Serializable {
#Id
private Integer emplId;
private String name;
}
#Entity
public class Role implements Serializable {
#Id
private Integer roleTypeSeqNo;
private Integer reportsToRole;
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER, mappedBy="roleTypeSeqNo")
#JoinTable(
name="ASSIGNMENTS"
, joinColumns={#JoinColumn(name="ROLE_TYPE_SEQ_NO")}
, inverseJoinColumns={
#JoinColumn(name="EMPLID"),
#JoinColumn(name="PRIORITY_NO")
}
)
private List<Assignment> assignments;
}
public class HibernateUtil {
public static Object get(Class clazz, Serializable pkId) {
Session session = getSession();
Transaction transaction = session.beginTransaction();
Object obj = session.get(clazz, pkId);
transaction.commit();
session.close();
return obj;
}
public static List pagedQuery(Class clazz, List<Criterion> criterion, Integer start, Integer size){
Session session = getSession();
try {
Transaction transaction = session.beginTransaction();
DetachedCriteria dCriteria = DetachedCriteria.forClass(clazz);
for(Criterion c : criterion){
dCriteria.add(c);
}
dCriteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
dCriteria.setProjection(Projections.id());
Criteria criteria=session.createCriteria(clazz);
criteria.add(Subqueries.propertyIn("id", dCriteria));
criteria.setFirstResult(start);
criteria.setMaxResults(size);
List records = criteria.list();
transaction.commit();
return records;
} catch (Exception e) {
Logger.getLogger("HibernateUtil").log(Level.SEVERE, "There was an EXCEPTION THROWN!!!", e);
return null;
} finally {
session.close();
}
}
}
dCriteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
should be on the main criteria
criteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
Also there is no need for the subquery there. The following is enough
Criteria criteria = session.createCriteria(clazz);
for(Criterion c : criterions){
criteria.add(c);
}
criteria.setFirstResult(start);
criteria.setMaxResults(size);
List records = criteria.list();
i have write the criteria for company class.
below are company class, companySearch class and criteria. But criteria list is throw exception. exception is "org.hibernate.QueryException: could not resolve property: san.san of: com.sesami.common.domain.Company". How to access Company.san.san?
Company class
public class Company extends DomainObject implements UserDetails {
private Long id;
private String companyName;
private CompanyType companyType;
private String description;
private String companyURL;
private String billToEmail;
private String hashPassword;
private SAN san;
#OneToOne(cascade = { CascadeType.ALL })
public SAN getSan() {
return san;
}
public void setSan(SAN san) {
this.san = san;
}
...
}
CompanySearch
public class CompanySearch {
private String companyName;
private String email;
private Long san;
private String gstNumber;
......
public Long getSan() {
return san;
}
public void setSan(Long san) {
this.san = san;
}
...
}
Criteria
companyCriteria = this.getSession().createCriteria(
Company.class);
if (companySearch.getSan() != null
&& !"".equals(companySearch.getSan()))
companyCriteria.add(Restrictions.eq("san.san",
companySearch.getSan()));
Integer count = ((Long) companyCriteria.setProjection(
Projections.rowCount()).uniqueResult()).intValue();
companyCriteria.setProjection(null);
companyCriteria.setResultTransformer(Criteria.ROOT_ENTITY);
companyCriteria
.setFirstResult((pager.getPage() - 1) * pager.getPageSize())
.setMaxResults(pager.getPageSize()).list();
List<Company> companies = companyCriteria.list();
PagedResultSet pr = new PagedResultSet();
pr.setPager(pager);
pr.setResultSet(companies);
pr.setRowCount(count);
return pr;
You must create a join to the San entity, using a subcriteria, or an alias:
companyCriteria.createAlias("san", "sanAlias");
companyCriteria.add(Restrictions.eq("sanAlias.san",
companySearch.getSan()));
or
companyCriteria.createCriteria("san").add(Restrictions.eq("san",
companySearch.getSan()));
This is well explained in the Hibernate reference documentation and even in the Criteria javadoc.
Note that this has absolutely nothing to do with Spring, and everything to do with Hibernate. If you searched in the Spring doc for how to do this, no wonder you didn't find anything.