2013-06-07 6 views
5

Hibernate rzuca następujący wyjątek:(Hibernate) java.sql.SQLException: Pole „xxxx” nie ma wartości domyślnej

Caused by: java.sql.SQLException: Field 'catVerb_id' doesn't have a default value 

Ludzie mówią, że problem jest z moim PK, które nie mają instrukcja AUTO_INCREMENT, jednak widzisz, że zrobiłem to w mojej bazie danych i problem nadal występuje. Więc przyniosłem moje zajęcia i implementacje baz danych.

Myślę, że mój problem dotyczy klasy testowej ... Ktoś może mi pokazać, jak mogę to przetestować?

(Tak, niektóre wyrazy są po portugalsku, ale można je zrozumieć).

CategoriaVerbete

@Entity 
@Table(name="verbete_categoria") 
public class CategoriaVerbete implements Serializable{ 
    private long id; 
    private String nome; 
    private String descricao; 
    private int serie; 
    private Set<Verbete> verbetes = new HashSet<Verbete>(); 
    private Set<SignificadosVerbete> significados = new HashSet<SignificadosVerbete>(); 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    @Column(name="catVerb_id") 
    public long getId() { 
     return id; 
    } 
    public void setId(long id) { 
     this.id = id; 
    } 

    ... 

    @OneToMany(cascade = {CascadeType.ALL}) 
    @JoinColumn(name="catVerb_id", nullable = true) 
    public Set<Verbete> getVerbetes() { 
     return verbetes; 
    } 
    public void setVerbetes(Set<Verbete> verbetes) { 
     this.verbetes = verbetes; 
    } 

    @OneToMany(cascade = {CascadeType.ALL}) 
    @JoinColumn(name="catVerb_id", nullable = true) 
    public Set<SignificadosVerbete> getSignificados() { 
     return significados; 
    } 
    public void setSignificados(Set<SignificadosVerbete> significados) { 
     this.significados = significados; 
    } 

} 

Verbete

@Entity 
@Table(name="verbete") 
public class Verbete implements Serializable{ 
    ... 

    @ManyToOne 
    @JoinColumn(name="catVerb_id", insertable = false, updatable = false) 
    public CategoriaVerbete getCategoria() { 
     return categoria; 
    } 
    public void setCategoria(CategoriaVerbete categoria) { 
     this.categoria = categoria; 
    } 

    ... 
} 

SignificadosVerbete

@Entity 
@Table(name="verbete_significados") 
public class SignificadosVerbete { 
    ... 

    @ManyToOne(cascade = CascadeType.ALL) 
    @JoinColumn(name="catVerb_id", insertable = false, updatable = false) 
    public CategoriaVerbete getCategoria() { 
     return categoria; 
    } 
    public void setCategoria(CategoriaVerbete categoria) { 
     this.categoria = categoria; 
    } 

    ... 

} 

W bazie danych ...

CREATE TABLE verbete_categoria (
catVerb_id INT PRIMARY KEY NOT NULL AUTO_INCREMENT, 
catVerb_nome VARCHAR(100) UNIQUE, 
catVerb_descricao MEDIUMTEXT, 
catVerb_serie INT NOT NULL 
); 

Każda pomoc zostanie doceniona, dziękuję.

AKTUALIZACJA - problem rozwiązany

Cóż, spodziewałem się triumfalnie ścieżkę dźwiękową, ale jest ok ...

Właśnie po co ten link mówi:

https://www.ibm.com/developerworks/community/blogs/fd26864d-cb41-49cf-b719-d89c6b072893/entry/como_criar_relacionamento_onetomany_com_hibernate?lang=en

Czytałem, że to, co jest w tym łączu, nie jest zalecane w dokumentacji Hibernate, ale starałem się postępować zgodnie z zaleceniami i minął jeden tydzień, traktując błędy. Mam więc nadzieję, że to pomoże innym ludziom.

Dziękuję za wszystkie odpowiedzi.

+0

Zadeklaruj adnotacje nad identyfikatorem pola, a nie w metodzie pobierania. – fmodos

+0

Ale czytałem, że możemy definiować adnotacje nad metodami get lub nad polami i nie jest dobrze używać obu w tej samej klasie ... Czy czytałem źle? – vitorgreati

+0

nie jestem pewien, każde odwołanie, którego używam ... jest zadeklarowane na polu, gdzie go przeczytałeś? – fmodos

Odpowiedz

0

Jeśli używasz tej samej kolumny catVerb_id dla @JoinColumn jak

@JoinColumn(name="catVerb_id", nullable = true) 

Spróbuj zmienić ją

@JoinColumn(name="catVerb_id", insertable = false, updatable = false) 

i nie może być zerowa, ponieważ jest to klucz podstawowy w Twoim przypadku.

+0

Próbowałem, ale problem nadal występuje =/ – vitorgreati

+0

Spróbuj również: @GeneratedValue (strategia = GenerationType.IDENTITY) – Alex

+0

Dla OneToMany użyj OneToMany (targetEntity =, mappedBy =) zamiast JoinColumn – Alex

2

Zgadzam się z podanym linkiem. Działał po łączu. Jak zrozumiałam, usunięcie poniższej części działało dla mnie.

Przed:

@ManyToOne(cascade = CascadeType.ALL) 
@JoinColumn(name="catVerb_id", insertable = false, updatable = false) 

Po:

@ManyToOne(cascade = CascadeType.ALL) 
@JoinColumn(name="catVerb_id") 
+0

To również zadziałało dla mnie, jestem ciekawa, jak znaleźć solidną odpowiedź, dlaczego to działa. Będę aktualizować odpowiedź z tym, co dostanę w niedalekiej przyszłości –

3

wierzę, że jest to SignificadosVerbete wstawiania przyczyną problemu "nie może być zerowa" (zalecam włączyć śledzenia SQL, aby zobaczyć, które zapytania powoduje problem).

Jest to powszechny problem dla dwukierunkowej relacji jeden do wielu. To, co masz, to coś takiego:

class Foo { 
    @Id 
    @Column("foo_id") 
    Long id; 

    @OneToMany(cascade=ALL) 
    @JoinColumn("foo_id") 
    Set<Bar> bars; 
} 

class Bar { 
    @Id 
    @Column("bar_id") 
    Long id; 

    @ManyToOne 
    @JoinColumn("foo_id", insertable=false, updatable=false) 
    Foo foo; 
} 

Tego rodzaju mapowanie spowoduje, że związek będzie należał do Foo. A to utworzy wiele instrukcji insert + update: Kiedy wstawiasz Foo, z 2 Bar s, co się stanie, to najpierw wstawi Foo i 2 Bar bez FK foo_id. Następnie dla każdej aktualizacji zostanie wydana dwie aktualizacje: Bar, aby zaktualizować poprawną foo_id w tabeli Bar.

Normalnie nie są mapowanie dwukierunkowy mapping OneToMany tak, możemy to zrobić w zamian:

class Foo { 
    @Id 
    @Column("foo_id") 
    Long id; 

    @OneToMany(mappedBy="foo", cascade=ALL) 
    Set<Bar> bars; 
} 

class Bar { 
    @Id 
    @Column("bar_id") 
    Long id; 

    @ManyToOne 
    @JoinColumn("foo_id") 
    Foo foo; 
} 

Dzięki temu relacja jest owened przez Bar, a gdy wstawiasz jak to, co opisałem powyżej , będziesz wstawiać 1 Foo i 2 Bar s, które już mają foo_id jako część wstawki.

To zwykle sposób, w jaki wykonujemy dwukierunkową relację w Hibernate.

+0

oops, właśnie przeczytałem twoją aktualizację tego dokumentu, który wydaje się sugerować to, co opisałem tutaj. Nie można jednak odczytać portugalskiego: P –

+0

Jest to odpowiedź, na którą rozwiązano problem. Wielkie dzięki, Adrian! Nie wiedziałem, że te kwalifikatory (które można aktualizować, można je wstawić) wpłynęłyby na operacje. Chyba muszę się głęboko nauczyć, jak hiberante przekłada to na operacje sql. – gruszczy

+0

Cieszę się, że pomogę (wow, prawie 2 lata.). Rozważ zaakceptowanie odpowiedzi, jeśli rozwiąże ona Twój problem. –

1

java.sql.SQLException: Pole 'xxxx' nie ma wartości domyślnej

(aka pośredni kwestia obciążenia Fetch.LAZY.)

wpadłem na ten problem dzisiaj.

Okazało się, że to kilka problemów w mojej sytuacji.

Pierwszą rzeczą, którą musiałem naprawić, było to, że lista, o której mowa, musi być LICZĄ OBCIĄŻONA. I przez LAZY LOADED mam na myśli, że musi być dostępny z bazy danych, gdy baza danych "jest w sesji". Teraz jest mała sztuczka, którą znalazłem, gdy masz do czynienia z Fetch.LAZY, tak, że musisz (pozornie niepotrzebnie) wywołać metodę na obiekcie odniesienia, kiedy ładujesz ją do kontenera. Nie wystarczy tylko zwrócić referencję, nawet wewnątrz obiektu sesji.

Na przykład, zamiast po prostu mówiąc to:

public List<Apple> getApples(Kid kid) throws KidNotFoundException 
{ 
    log.info("getApples (service) called"); 
    kid = get(kid); 
    List<Apple> list = kid.getApples(); 
    return list; 
} 

Trzeba dodać jeszcze jeden pozornie nieistotne krok. Aby uruchomić mechanizm Lazy Load JPA, musisz wywołać metodę na samym obiekcie referencyjnym (i działa ona tylko w przypadku transakcji JPA, bezpośredniej lub dorozumianej za pomocą tagu @Stateless). Dopóki to zrobisz, JPA zrobi to najlepiej, aby nie ładować niepotrzebnych obiektów do pamięci (aka. cały pomysł za Fetch.LAZY).

Więc w tym przypadku I wywołać metodę na pobranym (oznaczenie Fetch.LAZY) Przedmiot „listy”:

list.size(); 

Każda metoda na obiekcie można nazwać wywołać JPA załadować obiekt (lub obiekty), w tym przypadku właśnie nazwałem metodę list.size(), była tak wygodna, że ​​nie wygląda tak nie na miejscu, jak tylko wywołanie pozornie niepotrzebnego kid.getName(); z profesjonalnego punktu widzenia. Jak bardzo chciałbym, aby dobry tutorial na temat Fetch.LAZY mógł mi to wszystko wskazać. Pasza dla innej książki, którą chyba ...

To zmusza JPA do rzeczywistego załadowania przywoływanego obiektu z bazy danych.

public List<Apple> getApples(Kid kid) throws KidNotFoundException 
{ 
    log.info("getApples (service) called"); 
    kid = get(kid); 
    List<Apple> list = kid.getApples(); 
    list.size(); 
    return list; 
} 

To był pierwszy numer generujący java.sql.SQLException „field«xxxx»nie mają wartości domyślne” post w moim przypadku.

Druga kwestia dotyczyła nieprawidłowo skonfigurowanej relacji @ManyToMany między dwiema tabelami. Dzisiaj, zajęło mi to około pięciu minut, aby ustawić to, co według mnie było relacją wiele do wielu z wcześniej stworzonego prototypu, jaki miałem. Szarpanie włosów zajęło mi około sześciu godzin, żeby się rozwinęły. W każdym razie właśnie to zrobiłem, aby rozwiązać moją sytuację.

/** 
* "Buckets" 
* an Apple can be give to 0-to-n Kids ... 
*/ 

@ManyToMany(cascade=CascadeType.PERSIST) 
@JoinTable(name="Buckets", 
    [email protected](name="Apple_id"), 
    [email protected](name="Kid_id")) 
private List<Kid> kids; 

public List<Kid> getKids() { 
    return kids; 
} 

public void setKids(List<Kid> kids) { 
    this.kids = kids; 
} 

. . .

/** 
* a Kid can have 0-n Apples 
*/ 

@ManyToMany(mappedBy="kids", cascade=CascadeType.PERSIST) 
private List<Apple> apples; 

To i fakt, że mój oryginalny setup @ManyToMany został odwołującego niewłaściwy tabeli przyczyniły się do tego błędu w moim przypadku. Ale proste naprawienie sytuacji LAZY LOAD rozwiązało problem "java.sql.SQLException: Field" xxxx "nie ma domyślnej wartości".

Perry

Ps. Po całym dniu nauczyłem się kilku zgrabnych sztuczek ukrytych pod chropowatą powierzchnią WZP (aka surfując po sieci i czytając dokumenty na temat efektywnego korzystania z relacji @ManyToMany). Taki, że powyższa konfiguracja dynamicznie utworzy trzecią tabelę bazy danych, która wygląda tak dobrze, jak gdyby była tworzona ręcznie. Wymusza również wyjątkową relację między dziećmi i jabłkami, jeśli chodzi o relację jeden-do-jednego. Jak również utworzyć tylko jedną dodatkową tabelę w bazie danych, zamiast potrzeby dwóch identycznych tabel w bazie danych. W efekcie, w moim przypadku miałem 2 stoły przed tym @ManyToMany konstruktem:

dzieci Jabłka

W wyniku @ ManyTo @ Wiele konstrukcji wymienionych powyżej tak jak ja teraz mam 3:

dzieci Jabłka chwytaki

wewnątrz tabeli Łyżki są tylko dwa pola, Apple_id i Kid_id i co ważne jest to, że po dodaniu wpisu do obu:

kids.add(apple); 
apple.add(kids); 

W tabeli Łyżki jest tylko JEDEN rekord, a nie dwa! Co jest bardzo ważne, jeśli próbujesz użyć Listy <> w miejsce zestawu <>, (również unikatowego).

Powiązane problemy