This week's book giveaway is in the Agile and Other Processes forum.
We're giving away four copies of The Little Book of Impediments (e-book only) and have Tom Perry on-line!
See this thread for details.
Win a copy of The Little Book of Impediments (e-book only) this week in the Agile and Other Processes forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

JPA, MySQL and @GeneratedValue

 
Antonio Fornie
Ranch Hand
Posts: 117
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello there. I'm new member at this forum though I've visited and read it many times.

I've got a problem. Hope you can help me, please. I'm using MySQL, Spring and jpa(hibernate).

Got two classes: Prueba and Inscripcion. Prueba has a Collection of Inscripcion, but in the DB inscripcion has a foreign key (id_prueba) to its prueba. Well, the problem is when I try to save the "prueba", hibernate JPA tells me

javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: could not insert: [model.Inscripcion]

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

It seems strange to me as it should generate the next id_prueba value for prueba. Please, can anybody help me?
---------


My code.

@Entity
public class Prueba {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="id_prueba")
private Integer id;

@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "id_prueba")
private Collection<Inscripcion> inscripciones = null;

//getters and setters
}

@Entity
public class Inscripcion {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="id_inscripcion")
private Integer id;

//getters and setters
}

My DDL is this:
CREATE TABLE prueba(
id_prueba integer unsigned PRIMARY KEY AUTO_INCREMENT,
nombre varchar(16)
)


CREATE TABLE inscripcion(
id_inscripcion integer unsigned PRIMARY KEY AUTO_INCREMENT,
id_prueba integer unsigned NOT NULL,
FOREIGN KEY (id_prueba) REFERENCES prueba(id_prueba)
)


Thank you very much.
[ August 07, 2008: Message edited by: Antonio Fornie ]
 
Kuladip Yadav
Ranch Hand
Posts: 162
Hibernate Java Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Well, the problem is when I try to save the "prueba", hibernate JPA tells me

javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: could not insert: [model.Inscripcion]

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


How you save prueba ?
Since id_prueba is not null so while saving it throw exception.



According to your entity classes your schema should be like that


CREATE TABLE prueba(
id_prueba integer unsigned PRIMARY KEY AUTO_INCREMENT,
nombre varchar(16),
id_inscripcion integer unsigned NOT NULL,
FOREIGN KEY (id_inscripcion ) REFERENCES prueba(id_inscripcion )

)

CREATE TABLE inscripcion(
id_inscripcion integer unsigned PRIMARY KEY AUTO_INCREMENT,

)
 
Antonio Fornie
Ranch Hand
Posts: 117
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
First of all, thank you for your reply.

About the schema, a "prueba" has many "inscripcion", an "inscripcion" has ONLY one "prueba". So I don't agree that "prueba" should have a foreign key pointing "inscripcion", but "inscripcion" a foreign key pointing to "prueba". Don't you think so?

What do you mean by "Since id_prueba is not null so while saving it throw exception". I think that id_prueba is null and I think it MUST BE null, because the insert mustn't set any value as id_prueba is an AUTO_INCREMENT. Am I wrong? It may be the cause, but I just can't set the value because is the DB who knows the next id_prueba value.

Anyway, that's the way I save a "prueba":
--------------------------------------------------------------
@Transactional
public class PruebaServiceImpl implements PruebaService {
private EntityManager em;

@PersistenceContext
public void setEntityManager(EntityManager em) {
this.em = em;
}

@SuppressWarnings("unchecked")
public List<Prueba> findAll() {
Query query = getEntityManager().createQuery("select p FROM Prueba p");
return query.getResultList();
}

public void save(Prueba prueba) {

if (prueba.getId() == null) {
// new
em.persist(prueba);
} else {
// update
em.merge(prueba);
}
}

public void remove(int id) {
Prueba prueba = find(id);
if (prueba != null) {
em.remove(prueba);
}
}

private EntityManager getEntityManager() {
return em;
}

public Prueba find(int id) {
return em.find(Prueba.class, id);
}

}
--------------------------------------------------------------

Thank you very much. I'll be waiting for your reply.
[ August 07, 2008: Message edited by: Antonio Fornie ]
 
Kuladip Yadav
Ranch Hand
Posts: 162
Hibernate Java Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
About the schema, a "prueba" has many "inscripcion", an "inscripcion" has ONLY one "prueba". So I don't agree that "prueba" should have a foreign key pointing "inscripcion", but "inscripcion" a foreign key pointing to "prueba". Don't you think so?


Yes, I was wrong .You are right, schema is ok.

I think , there is problem in @GeneratedValue(strategy=GenerationType.IDENTITY)

Will you please try
@GeneratedValue(strategy=GenerationType.AUTO)

for both Entities id.

Thank You
 
Mark Spritzler
ranger
Sheriff
Posts: 17278
6
IntelliJ IDE Mac Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
in the "//getters and setters? part is one of them a Prueba object that you are mapping bi-directional? and didn't include a "mappedBy" attribute?

Mark
 
Antonio Fornie
Ranch Hand
Posts: 117
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks for your replays.

Kuldeep Yadav: I tried first with that value, it seems to be no difference.

Mark Spritzler: "Inscripcion" musn't know about "Prueba". Imagine prueba had a <<private GregorianCalendar date>>. That date shouldn't know is part of a "Prueba". It's the same. Isn't there a way to do it without having a navigability from "Inscripcion" to "Prueba"? I've seen many examples and they all do it your way, they have a bidirectional relation. But don't you think that's quite odd? It seems the most logical to me to have a unidirectional relation.

Thank you very much again. Hope anybody can help me, please.
 
Antonio Fornie
Ranch Hand
Posts: 117
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It seems there's no way to do what I was trying. I mean it's required to have a "Prueba prueba" refernce in my "Inscripcion" class. Unless I use a Join Table, what I think is even worse.

That's a pity, because it violates an OO principle. I'd like Inscripcion not to know anything about prueba. I've changed it, now Inscripcion has a Prueba and it works. I guess I'm a little disappointed with JPA, but has Hibernate the same problem?

Thank you very much.

By the way, that's the post I've just read. You see, it's Mike Keith who speaks It's a good source of knowledge

http://www.coderanch.com/t/218058/ORM/java/testing-jpa-OneToMany

Bye
 
Tim Holloway
Saloon Keeper
Posts: 18367
56
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The problem is that your model isn't just the individual tables, it's the fact that the two tables are related. You want it both ways - the benefits of a parent-child relationship but without the responsibility.

In fact, your problem isn't with the ORM, it's with the schema. When you explicitly defined your parent foreign key as not NULL, you REQUIRED the underlying database table to know about its parent. JPA isn't even really involved here. If you attempted to SQL CREATE an inscripcion without pointing it to a prueba, you'd fail even if you did it outside of Java entirely. Which is why you got a SQL (JDBC) error instead of a JPA error.

If you lift the NOT NULL constraint, you don't have to define the reverse mapping in JPA. Unless you want to.
 
Antonio Fornie
Ranch Hand
Posts: 117
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thank you for your reply Tim.

I don't know if I understand what you mean. How should I've done it then?

About what you said, I DO want the responsibility. I DO want MySql not to let me insert a "inscripcion" without a "prueba", it's just the constraint I need. What's wrong about that?

That's the way I know for a OneToMany relation in a relational DB. But in Java I have a "prueba" object with a Colecction<Inscripcion>. Of course I don't try to save the "inscripcion" without a "prueba". In fact what I try it's to save the "prueba", but JPA tries to save first the "inscripcion" and it doesn't find its "prueba" as long as I don't include a reference in "inscripcion" to its "prueba". That's what they say in the link I gave you, and it seems everybody is facing the same problem. It's a JDBC problem, you are right, but it's because JPA doesn't know about the "prueba" wich indeed exists and is linked at Java level to all of its "inscripcion" instances. It's linked in the inverse way, but I tried to save it in the inverse way: I tried to save the parent: prueba.

Please, can you tell why is wrong about requiring inscripcion table to know about prueba table? Which is the correct way for a OneToMany relationship? I'd like to understand you but I think I don't. Thank you very much for your reply. I'd really like to know what should I change.
[ August 11, 2008: Message edited by: Antonio Fornie ]
 
Jitmer Jijo
Greenhorn
Posts: 6
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The Field 'id_prueba' doesn't have a default value - errors like this can be avoided by removing any 'auto increment ' clause in table creation script and commenting out any
GenerationType. declaration/annotation in java as shown @Id
// @GeneratedValue(strategy = GenerationType.IDENTITY)

Then you will have control on what value you pass and database will take it.
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic