MySQL Hibernate中的空指针异常HQL

时间:2017-03-04 14:57:27

标签: java mysql hibernate jpa

目前我正在学习Hibernate,因此我使用以下三种方式在MySQL中创建数据库(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);

我尝试使用Hibernate做的事情等同于这个SQL查询

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';

我创建了这样的映射类:
Service

@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上课

@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上课

@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;
}
}

我还创建了HibernateUtil类来处理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();
}
}

Main类看起来像这样:

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();
}
}

但是错误说查询有问题,我真的不知道哪些是错的

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)  

修改
Maciej Kowalski的回答有所帮助,但我仍然得到了一些奇怪的和不需要的输出,顺便说一下主要没有退出(正如它应该的那样),而是“悬挂”#。我高举黄色正确的输出。 enter image description here

1 个答案:

答案 0 :(得分:2)

这里有一些事情......

首先,您正在尝试进行投影(如果您想处理返回的数据,但不更新它,这是一件好事),并希望获得实体列表。不这样做。

第二次,您以错误的方式引用列。标准是使用别名并从那里继续(更容易阅读和维护)。

所以,考虑到这些,我会:

1)为投影创建一个特殊的结果类,以便更容易使用该查询。它还可以节省大量的锅炉板代码解析:

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)将查询更改为以下内容:

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)如果您打算真正获得整个服务实体,请使用此查询:

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();

侧面

由于此处有一些连接,因此您可能需要添加distinct以不获得冗余结果。