org.hibernate.MappingException: impossible de déterminer le type de: java.util.List, à la table: Collège, pour les colonnes: [org.hibernate.mapping.Column (étudiants)]

96

J'utilise Hibernate pour toutes les opérations CRUD de mon projet. Cela ne fonctionne pas pour les relations un-à-plusieurs et plusieurs-à-un. Cela me donne l'erreur ci-dessous.

org.hibernate.MappingException: Could not determine type for: java.util.List, at table: College, for columns: [org.hibernate.mapping.Column(students)]

Puis à nouveau, j'ai parcouru ce didacticiel vidéo . C'est très simple pour moi, au début. Mais je ne peux pas le faire fonctionner. C'est aussi maintenant, dit

org.hibernate.MappingException: Could not determine type for: java.util.List, at table: College, for columns: [org.hibernate.mapping.Column(students)]

J'ai effectué des recherches sur Internet, quelqu'un a signalé un bogue dans Hibernate , et certains disent qu'en ajoutant @GenereatedValue, cette erreur sera effacée, mais cela ne fonctionne pas pour moi.

College.java

@Entity
public class College {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int collegeId;
private String collegeName;


private List<Student> students;

@OneToMany(targetEntity=Student.class, mappedBy="college", fetch=FetchType.EAGER)
public List<Student> getStudents() {
    return students;
}
public void setStudents(List<Student> students) {
    this.students = students;
}//Other gettters & setters omitted

Student.java

@Entity
public class Student {


@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int studentId;
private String studentName;


private College college;

@ManyToOne
@JoinColumn(name="collegeId")
public College getCollege() {
    return college;
}
public void setCollege(College college) {
    this.college = college;
}//Other gettters & setters omitted

Main.java:

public class Main {

private static org.hibernate.SessionFactory sessionFactory;

  public static SessionFactory getSessionFactory() {
    if (sessionFactory == null) {
      initSessionFactory();
    }
    return sessionFactory;
  }

  private static synchronized void initSessionFactory() {
    sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();

  }

  public static Session getSession() {
    return getSessionFactory().openSession();
  }

  public static void main (String[] args) {
                Session session = getSession();
        Transaction transaction = session.beginTransaction();
        College college = new College();
        college.setCollegeName("Dr.MCET");

        Student student1 = new Student();
        student1.setStudentName("Peter");

        Student student2 = new Student();
        student2.setStudentName("John");

        student1.setCollege(college);
        student2.setCollege(college);



        session.save(student1);
        session.save(student2);
        transaction.commit();
  }


}

Console:

 Exception in thread "main" org.hibernate.MappingException: Could not determine type  for: java.util.List, at table: College, for columns:  [org.hibernate.mapping.Column(students)]
at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:306)
at org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:290)
at org.hibernate.mapping.Property.isValid(Property.java:217)
at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:463)
at org.hibernate.mapping.RootClass.validate(RootClass.java:235)
at org.hibernate.cfg.Configuration.validate(Configuration.java:1330)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1833)
at test.hibernate.Main.initSessionFactory(Main.java:22)
at test.hibernate.Main.getSessionFactory(Main.java:16)
at test.hibernate.Main.getSession(Main.java:27)
at test.hibernate.Main.main(Main.java:43)

Le XML:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
    <!-- Database connection settings -->
    <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="connection.url">jdbc:mysql://localhost:3306/dummy</property>
    <property name="connection.username">root</property>
    <property name="connection.password">1234</property>
    <!-- JDBC connection pool (use the built-in) -->
    <property name="connection.pool_size">1</property>
    <!-- SQL dialect -->
    <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
    <!-- Enable Hibernate's automatic session context management -->
    <property name="current_session_context_class">thread</property>
    <!-- Disable the second-level cache -->
    <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
    <!-- Echo all executed SQL to stdout -->
    <property name="show_sql">true</property>
    <!-- Drop and re-create the database schema on startup -->
    <property name="hbm2ddl.auto">update</property>

    <mapping class="test.hibernate.Student" />
    <mapping class="test.hibernate.College" />
</session-factory>

Karl Richter
la source
1
@All: Personne ne m'a parlé du mauvais placement du code dans Main.java :(
le problème peut être la création de l'objet liste
Kemal Duran
1
[éons plus tard] dans mon application de démarrage de printemps, @Access(AccessType.FIELD)(dans mon cas, je voulais utiliser FIELD) était le seul à le résoudre
Scaramouche

Réponses:

169

Vous utilisez la stratégie d'accès aux champs (déterminée par l'annotation @Id). Placez toute annotation relative à JPA juste au-dessus de chaque champ au lieu de la propriété getter

@OneToMany(targetEntity=Student.class, mappedBy="college", fetch=FetchType.EAGER)
private List<Student> students;
Arthur Ronald
la source
@Arthur Ronald FD Garcia: Merci, cela a très bien fonctionné. Mais, le programme est maintenant arrêté par un nouveau. object references an unsaved transient instance - save the transient instance before flushingConnaissez-vous cette erreur. Sinon, laissez-le. Je cherche.
@Arthur Ronald FD Garcia: Salut encore, j'ai vu une solution à mon erreur actuelle, que j'ai posée dans mon commentaire précédent. Voici le lien. stackoverflow.com/questions/1667177/... La solution est d'inclure cascade=CascadeType.ALL. Mais pour moi, cela montre une erreur et aucune suggestion dans mon éclipse. Savez-vous quelque chose à ce sujet. :)
9
@Arthur +1 Good catch @MaRaVan Vous pouvez utiliser soit une stratégie d'accès au champ, soit une stratégie d'accès à la propriété, mais vous devez être cohérent au sein d'une hiérarchie de classes, vous ne pouvez pas mélanger les stratégies, du moins pas dans JPA 1.0. JPA 2.0 permet cependant de mélanger les stratégies, mais vous auriez besoin d'annotations supplémentaires (et donc plus de complexité). Il est donc recommandé de choisir une stratégie et de la respecter dans votre application. Voir 2.2.2.2. Type d'accès .
Pascal Thivent
@Arthur Ronald FD Garcia: Hmmmm ... J'ai ajouté persistence.cascadeMaintenant c'est effacé. Mais j'obtiens à nouveau l'ancienne erreur object references an unsaved transient instance - save the transient instance before flushingANY Suggestions !!! : + |
@All: Personne ne m'a parlé du mauvais placement du code dans Main.java :(
78

L'ajout du @ElementCollectionchamp à la liste a résolu ce problème:

    @Column
    @ElementCollection(targetClass=Integer.class)
    private List<Integer> countries;
Biggy_java2
la source
5
+ targetClassn'est pas nécessaire car vous avez mentionné le type de la liste<Integer>
O.Badr
1
Cela semble nécessaire, car je cherchais une solution pour exactement ce problème et l'ajout de @ElementCollection (targetClass = String.class) à ma simple liste de chaînes l'a résolu.
Angel O'Sphere
32

Problème avec les stratégies d'accès

En tant que fournisseur JPA, Hibernate peut introspecter à la fois les attributs d'entité (champs d'instance) ou les accesseurs (propriétés d'instance). Par défaut, le placement de l' @Idannotation donne la stratégie d'accès par défaut. Lorsqu'il est placé sur un champ, Hibernate assumera un accès basé sur le champ. Placé sur le getter d'identifiant, Hibernate utilisera un accès basé sur les propriétés.

Accès basé sur le terrain

Lors de l'utilisation d'un accès basé sur les champs, l'ajout d'autres méthodes au niveau de l'entité est beaucoup plus flexible car Hibernate ne les considérera pas comme faisant partie de l'état de persistance

@Entity
public class Simple {

@Id
private Integer id;

@OneToMany(targetEntity=Student.class, mappedBy="college", 
fetch=FetchType.EAGER)
private List<Student> students;

//getter +setter
}

Accès basé sur la propriété

Lors de l'utilisation d'un accès basé sur les propriétés, Hibernate utilise les accesseurs pour lire et écrire l'état de l'entité

@Entity
public class Simple {

private Integer id;
private List<Student> students;

@Id
public Integer getId() {
    return id;
}

public void setId( Integer id ) {
    this.id = id;
}
@OneToMany(targetEntity=Student.class, mappedBy="college", 
fetch=FetchType.EAGER)
public List<Student> getStudents() {
   return students;
}
public void setStudents(List<Student> students) {
    this.students = students;
}

}

Mais vous ne pouvez pas utiliser à la fois un accès basé sur le champ et un accès basé sur la propriété. Cela montrera comme cette erreur pour vous

Pour plus d'idées, suivez ceci

JustCode
la source
9
@Access(AccessType.PROPERTY)
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name="userId")
public User getUser() {
    return user;
}

J'ai les mêmes problèmes, je l'ai résolu en ajoutant @Access(AccessType.PROPERTY)

user2406031
la source
dans mon application de démarrage de printemps, @Access(AccessType.FIELD)(dans mon cas, je voulais utiliser FIELD) était le seul à le résoudre
Scaramouche
2

Ne t'inquiète pas! Ce problème se produit en raison de l'annotation. Au lieu de l'accès basé sur le champ, l'accès basé sur la propriété résout ce problème. Le code comme suit:

package onetomanymapping;

import java.util.List;

import javax.persistence.*;

@Entity
public class College {
private int collegeId;
private String collegeName;
private List<Student> students;

@OneToMany(targetEntity = Student.class, mappedBy = "college", 
    cascade = CascadeType.ALL, fetch = FetchType.EAGER)
public List<Student> getStudents() {
    return students;
}

public void setStudents(List<Student> students) {
    this.students = students;
}

@Id
@GeneratedValue
public int getCollegeId() {
    return collegeId;
}

public void setCollegeId(int collegeId) {
    this.collegeId = collegeId;
}

public String getCollegeName() {
    return collegeName;
}

public void setCollegeName(String collegeName) {
    this.collegeName = collegeName;
}

}

pierre d'Aaron
la source
2

Insérez simplement l'annotation @ElementCollection sur votre variable de liste de tableaux, comme ci-dessous:

@ElementCollection
private List<Price> prices = new ArrayList<Price>();

J'espère que ça aide

Renato Vasconcellos
la source
C'est génial! Ça a marché comme sur des roulettes! Les autres réponses ne fonctionnent pas pour moi. Cela l'a vraiment fait. La réponse principale m'a juste fait entrer dans plus de problèmes que je devais aborder séparément de celui-ci. Bonne réponse!
Compilateur v2
2

Dans mon cas, il était stupide de manquer l'annotation @OneToOne, j'ai défini @MapsId sans elle

S.Dayneko
la source
1

Bien que je sois nouveau dans l'hibernation, mais avec peu de recherches (essais et erreurs, nous pouvons dire), j'ai découvert que cela était dû à une incohérence dans l'annotation des méthodes / fichiers.

lorsque vous annotez @ID sur une variable, assurez-vous que toutes les autres annotations sont également effectuées sur la variable uniquement et lorsque vous l'annotez sur la méthode getter, assurez-vous que vous annotez uniquement toutes les autres méthodes getter et non leurs variables respectives.

ShailendraChoudhary
la source
1

Au cas où quelqu'un d'autre atterrirait ici avec le même problème que j'ai rencontré. J'obtenais la même erreur que ci-dessus:

L'appel de la méthode init a échoué; l'exception imbriquée est org.hibernate.MappingException: impossible de déterminer le type de: java.util.Collection, à la table:

Hibernate utilise la réflexion pour déterminer quelles colonnes se trouvent dans une entité. J'avais une méthode privée qui commençait par «get» et renvoyait un objet qui était également une entité d'hibernation. Même les getters privés que vous souhaitez ignorer doivent être annotés avec @Transient. Une fois que j'ai ajouté l'annotation @Transient, tout a fonctionné.

@Transient 
private List<AHibernateEntity> getHibernateEntities() {
   ....
}
jbppsu
la source