2

My goal is to create my Contact object directly from query and hibernate, the peculiarities are mainly three:

  • The contact object has another custom object inside that is the Company.
  • The contact object contains many more fields and I just want to retrieve a few
  • To retrieve the values ​​I have to use a complex query that I cannot generate via a simple createCriteria using hibernate.

Contact

@Entity
@Table(name = "contacts")
public class Contact
{
    private String firstName;
    private String lastName;
    private Company company;

    ...
}

Company

@Entity
@Table(name = "companies")
public class Contact
{
    private Integer id;
    private String name;

    ...
}

SQL Query

As I explained before the query is very complex but for convenience both in writing and in answering the question I have reduced it to its minimum terms:

SELECT  a.first_name as firstName, 
        a.last_name as lastName, 
        a.company_id as companyId,
        b.company_name as companyName
FROM    contacts a
INNER JOIN companies b ON a.company_id = b.company_id

UserType (CompanyType)

To create the Company object I use a UserType and it is the following

public class CompanyType implements UserType
{

    @Override
    public int[] sqlTypes()
    {
        return new int[] { Types.INTEGER, Types.VARCHAR };
    }

    @SuppressWarnings("rawtypes")
    @Override
    public Class returnedClass()
    {
        return Company.class;
    }

    ...

}

Java

I am currently building my object in the following way and is it working.. currently thanks to my UserType I can create a new Company object and set the id.

Type companyType = session.getTypeHelper().custom(CompanyType.class);

results = session.createSQLQuery(SQL_QUERY)
        .addScalar("firstName", StandardBasicTypes.STRING)
        .addScalar("lastName", StandardBasicTypes.STRING)
        .addScalar("companyId", companyType)
        .setResultTransformer(Transformers.aliasToBean(Contact.class))
        .list();

My goal is to set the name of the Company in the same object created before (by the id).. I tried to add the following line of code but I get an error because it is trying to allocate a new object instead of setting the current one:

.addScalar("companyName", companyType)
G. Ciardini
  • 1,210
  • 1
  • 17
  • 32

2 Answers2

1

Not sure if I completely understand the problem, but do you want to set that the fields of the nested entity(Company) inside the Contact entity object? If that's the goal, then the simple AliasToBeanResultTransformer won't help for single-level entity transformation. For transformation involving nested entities, you will need to use an AliasToBeanNestedResultTransformer - like what samiandoni has contributed here - https://github.com/samiandoni/AliasToBeanNestedResultTransformer/blob/master/AliasToBeanNestedResultTransformer.java.

You can use it like so:-

results = session.createSQLQuery(SQL_QUERY)
        .addScalar("firstName", StandardBasicTypes.STRING)
        .addScalar("lastName", StandardBasicTypes.STRING)
        .addScalar("companyId", companyType)
        .setResultTransformer(new AliasToBeanNestedResultTransformer(Contact.class))
        .list();
  • I understand where you want to go and as a solution it would be perfect.. the fact is that what you propose is 8 years old, hibernate has been updated and some classes like `PropertyAccessor` and `PropertyAccessorFactory` are not present from version 5 onwards. – G. Ciardini Jun 28 '21 at 16:28
  • I guess there are now PropertyAccessStrategy and PropertyAccess classes that can give you similar results. Can we try something like this in the transformTuple method while setting nested properties? – Ashutosh Thakur Jul 03 '21 at 06:49
  • ```PropertyAccessStrategy accessor = PropertyAccessStrategyFieldImpl.INSTANCE; PropertyAccess access = accessor.buildPropertyAccess(subclass, (String) subclassToAlias.get(subclass).get(2)); access.getSetter().set(root, subObject, null); PropertyAccessStrategy accessor = PropertyAccessStrategyFieldImpl.INSTANCE; PropertyAccess access = accessor.buildPropertyAccess(subclass, (String) subclassToAlias.get(subclass).get(2)); access.getSetter().set(root, subObject, null);``` – Ashutosh Thakur Jul 03 '21 at 06:50
0

You can create a DTO object of selected fields and Transformed the query result to DTO.

Transformers.aliasToBean(ContactCompanyDTO.class)

 public class ContactCompanyDTO {
         private String firstName;
         private String lastName;
         private String companyName;
         private Integer id;
         
    }

If you want to use an actual Domain object then you can easily convert the DTO to a Domain object.

  • What I asked is different, my goal is to create my entity directly from hibernate. If I use your solution I would lose the entire structure of my entities with the relationship between contact and company. – G. Ciardini Jun 14 '21 at 12:45