2013-06-07 10 views
5

Hibernate sta gettando la seguente eccezione:(Hibernate) java.sql.SQLException: Il campo 'xxxx' non ha un valore predefinito

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

La gente dice che il problema è con i miei PK che non hanno l'istruzione AUTO_INCREMENT, tuttavia puoi vedere che ho fatto questo nel mio database e il problema continua. Quindi, ho portato le mie classi e le mie implementazioni di database.

Penso che il mio problema sia con la classe di test ... Qualcuno potrebbe mostrarmi come faccio a testarlo?

(Sì, alcune parole sono in portoghese, ma puoi capire).

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

    ... 

} 

Nel database ...

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

Qualsiasi aiuto sarà apprezzato, grazie.

AGGIORNAMENTO - PROBLEMA RISOLTO

Beh, mi aspettavo una colonna sonora trionfante, ma è ok ...

ho solo seguito quello che dice questo link:

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

Ho letto che ciò che è in quel collegamento non è raccomandato dalla documentazione di Hibernate, ma ho provato a seguire i consigli e ho passato una settimana a trattare gli errori. Quindi, spero che questo aiuti le altre persone.

E grazie per tutte le risposte.

+0

Dichiarare le annotazioni sul campo id e non nel metodo get. – fmodos

+0

Ma ho letto che possiamo definire annotazioni sui metodi get o sui campi e che non va bene usare entrambi nella stessa classe ... Ho letto male? – vitorgreati

+0

non sono sicuro, ogni riferimento che uso ... è dichiarato sul campo, dove l'hai letto? – fmodos

risposta

0

Se si utilizza la stessa colonna catVerb_id per @JoinColumn come

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

cercare di cambiarlo a

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

e non può essere nullo perché è chiave primaria nel tuo caso.

+0

Ho provato, ma il problema persiste =/ – vitorgreati

+0

Provare anche: @GeneratedValue (strategy = GenerationType.IDENTITY) – Alex

+0

Per OneToMany utilizzare OneToMany (targetEntity =, mappedBy =) anziché JoinColumn – Alex

2

Sono d'accordo con il collegamento fornito. Ha funzionato seguendo il link. Come ho capito, lo rimuovere la parte sottostante ha funzionato per me.

Prima:

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

Dopo:

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

Questo ha funzionato anche per me, sono curioso di sapere una risposta solida perché funziona. Aggiornerò la risposta con quello che otterrò nel prossimo futuro –

3

Credo che sia l'inserimento SignificadosVerbete causa il problema "non può essere nullo" (consiglio caldamente di attivare traccia di SQL per vedere quale interrogazione sta causando problemi).

È un problema comune per la relazione bi-direzionale uno-a-molti. Quello che hai è qualcosa del tipo:

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

Questo tipo di mappatura farà sì che il rapporto sia di proprietà di Foo. E questo creerà più istruzioni insert + update: quando si inserisce uno Foo, con 2 Bar s, ciò che accadrà è, per prima cosa, verrà inserito Foo e 2 Bar senza l'FK foo_id. Quindi verranno emessi due aggiornamenti per ogni Bar per aggiornare il foo_id corretto nella tabella Bar.

Normalmente non stiamo mappando mappatura OneToMany bidirezionale come questo, facciamo questo, invece:

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

In questo modo, il rapporto è owened da Bar, e quando si sta inserendo come quello che ho descritto sopra , inserirai 1 Foo e 2 Bar s che hanno già foo_id come parte dell'inserto.

Questo è normalmente il modo in cui facciamo una relazione bidirezionale in Hibernate.

+0

oops, ho appena letto l'aggiornamento di quel documento, che sembra suggerire ciò che stavo descrivendo qui. Impossibile leggere il portoghese: P –

+0

Questa è la risposta che ha risolto il problema. Grazie mille, Adrian! Non sapevo che questi qualificatori (aggiornabili, inseribili) avrebbero influito sulle operazioni. Credo di aver bisogno di educarmi profondamente su come hiberante traduce questo in operazioni sql. – gruszczy

+0

Felice di aiutarlo (wow, quasi 2 anni.). Considera di accettare la risposta se risolve il tuo problema. –

1

java.sql.SQLException: Il campo 'xxxx' non ha un valore predefinito

(aka indiretta problema carico Fetch.LAZY.)

mi sono imbattuto in questo problema oggi.

Si è rivelato un paio di problemi nella mia situazione.

La prima cosa che ho trovato che doveva essere risolto era che l'elenco in questione doveva essere CARICATO. E per LAZY LOADED intendo che deve essere accessibile dal database quando il database "è in sessione". Ora c'è un piccolo trucco che ho trovato che devi fare quando hai a che fare con Fetch.LAZY, in modo tale che devi (apparentemente inutilmente) chiamare un metodo sull'oggetto di riferimento quando lo carichi nel contenitore. Non è sufficiente restituire il riferimento, anche all'interno dell'oggetto della sessione.

Per esempio, invece di dire semplicemente questo:

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

È necessario aggiungere un passo in più apparentemente insignificante. Per attivare il meccanismo Lazy Load di JPA è necessario chiamare un metodo sull'oggetto di riferimento stesso (e funziona solo all'interno di una transazione JPA, sia diretta che implicita tramite un tag @Stateless). Finché non lo farai, JPA farà del suo meglio per non caricare oggetti non necessari nella memoria (alias l'intera idea alla base di Fetch.LAZY).

Quindi, in questo caso io chiamo un metodo sul (denominazione Fetch.LAZY) oggetto 'lista' richiamato:

list.size(); 

Qualsiasi metodo sull'oggetto può essere chiamato per innescare APP a caricare l'oggetto (o oggetti), in questo caso ho appena chiamato il metodo list.size() è stato così conveniente, non sembra fuori luogo tanto quanto solo chiamare un kid.getName() apparentemente inutile(); dal punto di vista professionale. Come vorrei che un buon tutorial su Fetch.LAZY mi avesse indicato tutto questo. Foraggio per un altro libro immagino ...

Ciò impone al JPA di caricare effettivamente l'oggetto di riferimento dal database.

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

Questo è stato il primo numero che genera il 'java.sql.SQLException: Il campo 'xxxx' non ha un valore predefinito' un messaggio nel mio caso.

Il secondo problema ha riguardato una relazione @ManyToMany configurata in modo errato tra le due tabelle. Oggi, ci sono voluti circa cinque minuti per impostare quello che pensavo fosse un rapporto molti-a-molti da un prototipo precedentemente creato che avevo. Ci sono volute circa sei ore per tirare fuori i nodi. In ogni caso, questo è quello che ho fatto per risolvere la mia situazione.

/** 
* "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; 

Questo e il fatto che la mia messa a punto @ManyToMany originale è stato riferimento a tavolo sbagliato contribuito a questo errore nel mio caso. Ma il semplice aggiustamento della situazione LOZY LOAD ha risolto immediatamente il problema "java.sql.SQLException: Field" xxxx "non ha un valore predefinito".

Perry

Ps. Dopo tutto il giorno, ho imparato alcuni trucchi netti nascosti sotto l'esterno ruvido di JPA (ovvero navigare sul Web e leggere i documenti su come utilizzare le relazioni @ ManyToMany in modo efficiente). In modo tale che la suddetta configurazione crei dinamicamente una terza tabella di database che sembra buona come se l'avessi creata a mano. Riguarda anche la relazione unica tra bambini e mele per quanto riguarda una relazione uno-a-uno. Oltre a creare solo una tabella aggiuntiva nel database, anziché richiedere due tabelle identiche nel database. In effetti, nel mio caso ho avuto 2 tavoli prima di questo @ManyToMany costrutto:

bambini Mele

Come risultato della @ @ ManyTo Molti costrutto elencato appena come sopra Ora ho 3:

bambini Mele Benne

all'interno della tabella Benne ci sono solo due campi, Apple_id e Kid_id e cosa importante è che quando aggiungo una voce a entrambi:

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

C'è solo un record nella tabella Benetti e non due! Il che è molto importante se si sta tentando di utilizzare l'Elenco <> al posto di un Set <> (noto anche come unico).

Problemi correlati