Dlaczego pojawia się komunikat o błędzie „Wartość null została przypisana do właściwości ustawiacza typów pierwotnych” podczas używania HibernateCriteriaBuilder w Grails

100

Otrzymuję następujący błąd podczas używania prymitywnego atrybutu w moim obiekcie domeny Grails:

Null value was assigned to a property of primitive type setter of MyDomain.myAttribute
 org.hibernate.PropertyAccessException: Null value was assigned to a property of primitive type setter of MyDomain.myAttribute
at grails.orm.HibernateCriteriaBuilder.invokeMethod(HibernateCriteriaBuilder.java:1077)
Piotr
źródło
nie psuj wprowadzanych danych i nie będziesz musiał używać innych niż prymitywne opakowania. Brakowało mi wpisania niektórych wartości i udało mi się naprawić ten błąd dodając go do bazy danych.
Goot

Odpowiedzi:

168

Zgodnie z tym wątkiem SO , rozwiązaniem jest użycie nieprymitywnych typów opakowań; np. Integerzamiast int.

Piotr
źródło
6
Wszystkie usługi Codehaus zostały zakończone.
Priyanshu Chauhan
46

Wartość null nie może być przypisana do typu pierwotnego, takiego jak int, long, boolean itp. Jeśli kolumna bazy danych odpowiadająca polu w twoim obiekcie może mieć wartość null, to twoje pole powinno być klasą opakowania, taką jak Integer, Long, Boolean itp.

Niebezpieczeństwo polega na tym, że Twój kod będzie działał poprawnie, jeśli w bazie danych nie będzie żadnych wartości null, ale zakończy się niepowodzeniem po wstawieniu wartości null.

Zawsze możesz zwrócić typ pierwotny z metody pobierającej. Dawny:

  private Integer num;

  public void setNum(Integer i) {
    this.num = i;
  }

  public int getNum() {
    return this.num;
  }

Ale w większości przypadków będziesz chciał zwrócić klasę opakowania.

Więc albo ustaw kolumnę DB, aby nie zezwalała na wartości null, albo użyj klasy opakowania.

MattC
źródło
13

Typ pierwotny nie może mieć wartości null. Rozwiązaniem jest więc zastąpienie typu pierwotnego pierwotną klasą opakowania w pliku tableName.java. Jak na przykład:

@Column(nullable=true, name="client_os_id")
private Integer client_os_id;

public int getClient_os_id() {
    return client_os_id;
}

public void setClient_os_id(int clientOsId) {
    client_os_id = clientOsId;
}

odnośnik http://en.wikipedia.org/wiki/Primitive_wrapper_class, aby znaleźć klasę opakowania typu pierwotnego.

Nhat Dinh
źródło
8

Postaram się, abyś zrozumiał na przykładzie. Załóżmy, że masz tabelę relacyjną (STUDENT) z dwiema kolumnami oraz ID (int) i NAME (String). Teraz, jako ORM, utworzyłbyś klasę encji mniej więcej następującą: -

package com.kashyap.default;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * @author vaibhav.kashyap
 *
 */
@Entity
@Table(name = "STUDENT")
public class Student implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = -1354919370115428781L;

    @Id
    @Column(name = "ID")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @Column(name = "NAME")
    private String name;

    public Student(){

    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

}

Załóżmy, że tabela zawiera już wpisy. Teraz, jeśli ktoś poprosi Cię o dodanie kolejnej kolumny „AGE” (liczba całkowita)

ALTER TABLE STUDENT ADD AGE int NULL

Będziesz musiał ustawić wartości domyślne na NULL, aby dodać kolejną kolumnę do wstępnie wypełnionej tabeli. To sprawia, że ​​dodajesz kolejne pole w klasie. Teraz pojawia się pytanie, czy do deklarowania pola będziesz używać pierwotnego typu danych, czy nieprymitywnego typu opakowującego danych.

@Column(name = "AGE")
private int age;

lub

@Column(name = "AGE")
private INTEGER age;

będziesz musiał zadeklarować pole jako niepymitywny opakowujący typ danych, ponieważ kontener będzie próbował zamapować tabelę na jednostkę. W związku z tym nie byłby w stanie odwzorować wartości NULL (domyślnie), gdybyś nie zadeklarował pola jako opakowania i ostatecznie wyrzuciłby komunikat „Wartość Null została przypisana do właściwości ustawiającej typ pierwotny” Wyjątek.

codechefvaibhavkashyap
źródło
6

użyj Integer jako typu i odpowiednio podaj setter / getter.

private Integer num;

public Integer getNum()...

public void setNum(Integer num)...
arn-arn
źródło
4

Nie używaj prymitywów w swoich klasach Entity , zamiast tego używaj ich odpowiednich opakowań. To rozwiąże ten problem.

Poza klasami Entity możesz użyć walidacji! = Null dla pozostałej części przepływu kodu.

Israelm
źródło
3

Albo całkowicie unikaj nullw DB przez NOT NULLi w jednostce Hibernate @Column(nullable = false)odpowiednio za pośrednictwem lub użyj Longwrappera zamiast swoich longprymitywów.

Prymityw nie jest przedmiotem, dlatego nie możesz go przypisać null.

am0wa
źródło
3

Są dwa sposoby

  • Upewnij się, że kolumna db jest niedozwolona null
  • Klasy opakowania użytkownika dla zmiennej typu pierwotnego, takiego jak, private int var;można zainicjować jakoprivate Integer var;
4302836
źródło
2

@Dinh Nhat, twoja metoda ustawiająca wygląda nieprawidłowo, ponieważ ponownie wstawiłeś tam typ prymitywny i powinno to być:

public void setClient_os_id(Integer clientOsId) {
client_os_id = clientOsId;
}
Kamiel Ahmadpour
źródło
2

Zmień typ parametru z prymitywnego na Object i wprowadź zerową kontrolę w metodzie ustawiającej. Zobacz przykład poniżej

public void setPhoneNumber(Long phoneNumber) {
    if (phoneNumber != null)
        this.phoneNumber = phoneNumber;
    else
        this.extension = 0l;
}
Sandeep Shankar Harikrishnan
źródło
2
@Column(name ="LEAD_ID")
private int leadId; 

Zmień na

@Column(name ="LEAD_ID")
private Integer leadId; 
Rakesh Yadav
źródło
1

Upewnij się, że pole myAttribute bazy danych zawiera wartość null zamiast zera.

Aravinthan K
źródło