1

Currently I'm learning Hibernate and so I created database in MySQL with three tables in following way (MWE)

create database `fakturowanie`;
use `fakturowanie`;

drop table if exists `wykupione_uslugi`; #table 'bought services'
drop table if exists `uslugi`; #table 'services'
drop table if exists `kontrahenci`; table 'contractors'

create table `kontrahenci`(
`kontrahent_id` int unsigned auto_increment primary key,
`nazwisko` varchar(80), #surname
`imie` varchar(30), #name
`firma_nazwa` varchar(100), #company name
`nip_pesel` varchar(20) not null unique, #person ID
`ulica_nr_mieszkania` varchar(100), #street
`kod_pocztowy` varchar(6), #postal code
`miejscowosc` varchar(30), #city
`sposob_zaplaty` varchar(7) not null default 'gotówka', #payment method default cash
`uwzglednij_numer_faktury` bool not null default true, #include invoice number
`alias` varchar(30) not null
)engine = InnoDB
default charset = utf8
collate = utf8_polish_ci;

create table `uslugi`(
`usluga_id` int unsigned auto_increment primary key,
`nazwa` varchar(80) not null, #name
`symbol_PKWIU/PKOB` varchar(10),
`jednostka` varchar(10) not null, #unit
`cena_jednostkowa_netto` decimal(6, 2) not null, #unit price
`stawka_vat` int(2) unsigned not null #tax rate
)engine = InnoDB
default charset = utf8
collate = utf8_polish_ci;

create table `wykupione_uslugi`(
`id` int unsigned auto_increment primary key,
`kontrahent_id` int unsigned not null,
`usluga_id` int unsigned not null,
foreign key(kontrahent_id) references kontrahenci(kontrahent_id),
foreign key(usluga_id) references uslugi(usluga_id)
)engine = InnoDB
default charset = utf8
collate = utf8_polish_ci;

insert into `kontrahenci` (
nazwisko, imie, firma_nazwa, nip_pesel, ulica_nr_mieszkania, kod_pocztowy, miejscowosc,     sposob_zaplaty, uwzglednij_numer_faktury, alias) 
values ('Best', 'John', 'Best Inc.', 111-111-111, 'Best Street 5', 11-111, 'Best Valley', 'cash', 1, 'test');

insert into `uslugi` (
nazwa, jednostka, cena_jednostkowa_netto, stawka_vat)
values (
'Best tutoring', 'hour', 1000.00, 0);

insert into `wykupione_uslugi` (kontrahent_id, usluga_id) values (1, 1);

What I'm trying to do using Hibernate is equivalent of this SQL query

select 
`uslugi`.`nazwa`,
`uslugi`.`symbol_PKWIU/PKOB`,
`uslugi`.`jednostka`,
`uslugi`.`cena_jednostkowa_netto`,
`uslugi`.`stawka_vat`
from 
`wykupione_uslugi`
left join `kontrahenci` on `wykupione_uslugi`.`kontrahent_id` = `kontrahenci`.`kontrahent_id`
left join `uslugi` on `wykupione_uslugi`.`usluga_id` = `uslugi`.`usluga_id`
where
`kontrahenci`.`alias` = 'test';

I created mapped classes like this:
Service class

@Entity
@Table(name="uslugi", schema = "fakturowanie")
public class Service
{
private int serviceID;
private String serviceName;
private String symbol;
private String unit;
private BigDecimal unitPrice;
private int tax;
private Collection<ServicesList> servicesLists;

@Id
@Column(name = "usluga_id", nullable = false)
@GeneratedValue(generator="increment")
@GenericGenerator(name="increment", strategy = "increment")
public int getServiceID()
{
    return serviceID;
}

public void setServiceID(int serviceID)
{
    this.serviceID = serviceID;
}

@Basic
@Column(name = "nazwa", nullable = false, length = 80)
public String getServiceName()
{
    return serviceName;
}

public void setServiceName(String serviceName)
{
    this.serviceName = serviceName;
}

@Basic
@Column(name = "symbol_PKWIU/PKOB", nullable = false, length = 10)
public String getSymbol()
{
    return symbol;
}

public void setSymbol(String symbol)
{
    this.symbol = symbol;
}

@Basic
@Column(name = "jednostka", nullable = false, length = 10)
public String getUnit()
{
    return unit;
}

public void setUnit(String unit)
{
    this.unit = unit;
}

@Basic
@Column(name = "cena_jednostkowa_netto", nullable = false, precision = 2)
public BigDecimal getUnitPrice()
{
    return unitPrice;
}

public void setUnitPrice(BigDecimal unitPrice)
{
    this.unitPrice = unitPrice;
}

@Basic
@Column(name = "stawka_vat", nullable = false)
public int getTax()
{
    return tax;
}

public void setTax(int tax)
{
    this.tax = tax;
}

@OneToMany(mappedBy = "servicesMapping")
public Collection<ServicesList> getServicesLists()
{
    return servicesLists;
}

public void setServicesLists(Collection<ServicesList> servicesLists)
{
    this.servicesLists = servicesLists;
}
}

Contractor class

@Entity
@Table(name = "kontrahenci", schema = "fakturowanie")
public class Contractor
{
private int contractorID;
private String surname;
private String name;
private String companyName;
private String taxpayerINum;
private String street;
private String postalCode;
private String city;
private PaymentMethod paymentMethod;
private byte includeInvoiceNum;
private String alias;
private Collection<ServicesList> servicesList;

@Id
@Column(name = "kontrahent_id", nullable = false)
@GeneratedValue(generator="increment")
@GenericGenerator(name="increment", strategy = "increment")
public int getContractorID()
{
    return contractorID;
}

public void setContractorID(int contractorID)
{
    this.contractorID = contractorID;
}

@Basic
@Column(name = "nazwisko", nullable = true, length = 80)
public String getSurname()
{
    return surname;
}

public void setSurname(String surname)
{
    this.surname = surname;
}

@Basic
@Column(name = "imie", nullable = true, length = 30)
public String getName()
{
    return name;
}

public void setName(String name)
{
    this.name = name;
}

@Basic
@Column(name = "firma_nazwa", nullable = true, length = 100)
public String getCompanyName()
{
    return companyName;
}

public void setCompanyName(String companyName)
{
    this.companyName = companyName;
}

@Basic
@Column(name = "nip_pesel", unique = true, length = 20, nullable = false)
public String getTaxpayerINum()
{
    return taxpayerINum;
}

public void setTaxpayerINum(String taxpayerINum)
{
    this.taxpayerINum = taxpayerINum;
}

@Basic
@Column(name = "ulica_nr_mieszkania", nullable = true, length = 100)
public String getStreet()
{
    return street;
}

public void setStreet(String street)
{
    this.street = street;
}

@Basic
@Column(name = "kod_pocztowy", nullable = true, length = 6)
public String getPostalCode()
{
    return postalCode;
}

public void setPostalCode(String postalCode)
{
    this.postalCode = postalCode;
}

@Basic
@Column(name = "miejscowosc", nullable = true, length = 30)
public String getCity()
{
    return city;
}

public void setCity(String city)
{
    this.city = city;
}

@Enumerated(EnumType.STRING)
@Column(name = "sposob_zaplaty", nullable = false, length = 7)
public PaymentMethod getPaymentMethod()
{
    return paymentMethod;
}

public void setPaymentMethod(PaymentMethod paymentMethod)
{
    this.paymentMethod = paymentMethod;
}

@Basic
@Column(name = "uwzglednij_numer_faktury", nullable = false)
public byte getIncludeInvoiceNum()
{
    return includeInvoiceNum;
}

public void setIncludeInvoiceNum(byte includeInvoiceNum)
{
    this.includeInvoiceNum = includeInvoiceNum;
}

@Basic
@Column(name = "alias", nullable = false, length = 30)
public String getAlias()
{
    return alias;
}

public void setAlias(String alias)
{
    this.alias = alias;
}

@OneToMany(mappedBy = "contractorMapping")
public Collection<ServicesList> getServicesList()
{
    return servicesList;
}

public void setServicesList(Collection<ServicesList> servicesList)
{
    this.servicesList = servicesList;
}
}

ServicesList class

@Entity
@Table(name = "wykupione_uslugi", schema = "fakturowanie")
public class ServicesList
{
private int id;
private int contractorID;
private int serviceID;
private Contractor contractorMapping;
private Service servicesMapping;

@Id
@Column(name = "id", nullable = false)
@GeneratedValue(generator="increment")
@GenericGenerator(name="increment", strategy = "increment")
public int getId()
{
    return id;
}

public void setId(int id) {
    this.id = id;
}

@Basic
@Column(name = "kontrahent_id", nullable = false)
public int getContractorID() {
    return contractorID;
}

public void setContractorID(int contractorID) {
    this.contractorID = contractorID;
}

@Basic
@Column(name = "usluga_id", nullable = false)
public int getServiceID() {
    return serviceID;
}

public void setServiceID(int serviceID) {
    this.serviceID = serviceID;
}

@ManyToOne
@JoinColumn(name = "kontrahent_id", referencedColumnName = "kontrahent_id", insertable = false, updatable = false)
public Contractor getContractorMapping() {
    return contractorMapping;
}

public void setContractorMapping(Contractor contractorMapping) {
    this.contractorMapping = contractorMapping;
}

@ManyToOne
@JoinColumn(name = "usluga_id", referencedColumnName = "usluga_id", insertable = false, updatable = false)
public Service getServicesMapping() {
    return servicesMapping;
}

public void setServicesMapping(Service servicesMapping) {
    this.servicesMapping = servicesMapping;
}
}

I also created HibernateUtil class to handle SessionFactory

public class HibernateUtil
{
private static final SessionFactory sessionFactory = buildSessionFactory();

private static SessionFactory buildSessionFactory() {
    try {
        Configuration configuration = new Configuration();
        configuration.configure();

        StandardServiceRegistry standardRegistry = new StandardServiceRegistryBuilder()
                .configure()
                .build();

        return configuration.buildSessionFactory(standardRegistry);
    }
    catch(Exception e) {
        throw new ExceptionInInitializerError(e);
    }
}

public static Session getSession()
{
    return sessionFactory.openSession();
}

public static void close()
{
    sessionFactory.close();
}
}

And Main class looks like this:

public class Main
{
public static void main(String[] args)
{
    Session session = HibernateUtil.getSession();
    session.beginTransaction();

    List<Service> services = session.createQuery(
            "select Service.serviceName, Service.symbol, Service.unit, Service.unitPrice, Service.tax " +
                    "from ServicesList " +
                    "left join ServicesList.contractorMapping left join ServicesList.servicesMapping " +
                    "where Contractor.alias = 'test'").list();

    for(Service s : services)
    {
        System.out.println(s.getServiceID() + "\t" + s.getServiceName() + "\t" + s.getSymbol() + "\t" + s.getUnit() +
                "\t" + s.getUnitPrice() + "\t" + s.getTax());
    }

    session.getTransaction().commit();
    session.close();
}
}

but the error says that's something wrong with query and I don't really know what can be wrong

Exception in thread "main" java.lang.NullPointerException
at java.lang.String$CaseInsensitiveComparator.compare(String.java:1192)
at java.lang.String$CaseInsensitiveComparator.compare(String.java:1186)
at java.util.TreeMap.getEntryUsingComparator(TreeMap.java:376)
at java.util.TreeMap.getEntry(TreeMap.java:345)
at java.util.TreeMap.get(TreeMap.java:278)
at org.hibernate.dialect.function.SQLFunctionRegistry.findSQLFunction(SQLFunctionRegistry.java:45)
at org.hibernate.hql.internal.ast.util.SessionFactoryHelper.findSQLFunction(SessionFactoryHelper.java:369)
at org.hibernate.hql.internal.ast.tree.IdentNode.getDataType(IdentNode.java:374)
at org.hibernate.hql.internal.ast.HqlSqlWalker.lookupProperty(HqlSqlWalker.java:652)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.propertyRef(HqlSqlBaseWalker.java:1140)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.joinElement(HqlSqlBaseWalker.java:3838)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromElement(HqlSqlBaseWalker.java:3701)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromElementList(HqlSqlBaseWalker.java:3579)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromClause(HqlSqlBaseWalker.java:718)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:574)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:311)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:259)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:261)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:189)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:141)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:115)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:77)
at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:153)
at org.hibernate.internal.AbstractSharedSessionContract.getQueryPlan(AbstractSharedSessionContract.java:545)
at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:654)
at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:102)
at Main.main(Main.java:12)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)  

EDIT
Answer by Maciej Kowalski helped but still I'm getting some weird and unwanted output, btw main does not exit (as it supposed to) but is 'hanging'. I highlited yellow correct output. enter image description here

1 Answer 1

2

There are a few things here..

First, you are trying to make projection (which is a good thing if you want to work on the returned data, but not update it) and expecting to get a List of entities. Does not work that way.

Second, you are referencing the columns in a wrong way. The standard is to use an alias and go on from there (so much easier to read and maintain).

So, having those in mind i would:

1) Create a special result class for the projection, so that it would be easier to work with that query. It will also save you tons of boiler plate code parsing:

package com.mypkg;    

public class ServiceResult{

   private String serviceName;
   private String symbol;
   private String unit;
   private BigDecimal unitPrice;
   private int tax;

    public ServiceResult(String serviceName, String symbol
      ,String unit, BigDecimal unitPrice, int tax){
      // set the field values
    }

}

2) Change the query to the following:

List<ServiceResult> services = session.createQuery(
     "select new com.mypkg.ServiceResult(service.serviceName
               ,service.symbol, service.unit
               , service.unitPrice, service.tax) " +
     "from ServicesList serviceList" +
     "  left join serviceList.contractorMapping contractor" + 
     "  left join serviceList.servicesMapping service" +
     "where contractor.alias = 'test'")
     .list();

3) IF your intention was to actually get the whole Service entities, then use this query:

List<Service> services = session.createQuery(
     "select service " +
     "from Service service" +
     "  left join service.servicesLists servicesLists" + 
     "  left join servicesLists.contractorMapping contractor" +
     "where contractor.alias = 'test'")
     .list();

On the side

As there are a few joins going on here, so you might need to add distinct to not get redundant results.

Sign up to request clarification or add additional context in comments.

9 Comments

Honestly if it comes to mapping I wrote it basing on the one generated by IntelliJ
I used your 1) and 2) and it kinda works but still I'm getting some unwanted output, please see edit
Looks good to me.. in java can you retrieve the ServiceResult objects?
What do you mean "in java can you retrieve the ServiceResult objects"?
Typos.. should be servicesLists.. i have updated the option 3
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.