2

教師のリストが表示されるGUIがあります。2人はユーザーによって選択されます-彼らは作成される新しい学校のクラスのフォーム教師になります。教師とクラスの関係はnmです。

学校のクラス:(グループからIDを継承します)

@Entity
@Table(name="school_classes")
@Cacheable(true)
public class SchoolClass extends Group{

    @ManyToMany(cascade=CascadeType.ALL, mappedBy="classes", fetch=FetchType.EAGER)
    private SortedSet<Teacher> teachers;

先生:

  @Entity
    @Table(name="teachers")
    @Cacheable(true)
    public class Teacher extends creator.models.school.Entity{
            // name etc

    @ManyToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    @JoinTable(name="class_teachers",
    joinColumns = @JoinColumn(name="teacher_id", referencedColumnName="id"),
    inverseJoinColumns = @JoinColumn(name="class_id", referencedColumnName="id"))
    private SortedSet<SchoolClass> classes;

私はこのような新しいクラスを作成しようとしています:

String className = request.getParameter("class_name");
String id1 = request.getParameter("class_teacher1");
String id2  = request.getParameter("class_teacher2");
Teacher t1 = DataRetrieveModule.getTeacher(id1);
Teacher t2 = DataRetrieveModule.getTeacher(id2);


Layout l = new Layout();
SchoolClass newClass = new SchoolClass(className);
newClass.setLayout(l);
newClass.addTeacher(t1);
t1.addClass(newClass);

newClass.addTeacher(t2);
t2.addClass(newClass);
DataInsertionModule.insert(newClass);

このステートメントDataRetrieveModule.getTeacher(id1)はセッションを開き、IDで教師を取得して閉じます。 DataInsertionModule.insert(newClass)また、セッションを開き、を呼び出します session.saveOrUpdate(newClass)。(私も試しましたsession.merge(newClass)

教師の取得:

public static Teacher getTeacher(String id) {
        Session session = null;
        Teacher t = null;
        try{
            sessionFactory = MyFactory.getSessionFactory();
            session = sessionFactory.openSession();
            t = (Teacher) session.get(Teacher.class, Long.parseLong(id));

        }
        catch(Exception e) {
            System.out.println("in DAO:");
            e.printStackTrace();
            if(session!=null)
                session.close();
        }       
        finally{
            if(session!=null)
                session.close();
        }

        return t;
    }

データ挿入:

public static void insert(Object o) {
        Session session = null;

        try 
        {
            sessionFactory = MyFactory.getSessionFactory();
            session = sessionFactory.openSession();
            Transaction tx = session.beginTransaction();

            session.save(o);
            tx.commit();

            System.out.println("insertion done");
        }
        catch (Exception e)
        {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
        finally
        {
            if(session!=null)
                session.close();
        }
    }

しかし、挿入は機能しません。すでに存在する同じIDのオブジェクトが常に存在します。

a different object with the same identifier value was already associated with the session: [creator.models.school.Teacher#3]

私はstackoverflowを検索し、すべてのビジネスオブジェクトが継承するクラスのgetHashCodeおよびequalsメソッドをオーバーライドしました。

@Override
public int compareTo(Entity o) {
    if(this.id < o.getId())
        return -1;
    else if(this.id > o.getId())
        return 1;
    return this.getClass().getName().compareTo(o.getClass().getName());
}

@Override
public boolean equals(Object o) {
    if(o instanceof Entity)
        return this.compareTo((Entity)o)==0;
    else return this.equals(o);
}

@Override
public int hashCode() {

    char[] bla = this.getClass().getName().toCharArray();
    int blue=0;
    for(char c:bla)
        blue = blue*10 + c;
    return (int) (id+blue);

}

CascadeTypeさらに、のをに変更しようとしManyToManyましたMERGE(再び元に戻しました)。

現時点では、両方をsession.get(..)で取得した後、教師オブジェクトをマージします。これは、取得するとDBから大量のデータが取得されるためです。さらに ..ToMany関係があります。したがって、呼び出しによって両方の教師がロードされる可能性があります。

public static Object merge(Object o) {
        Session session = null;
        Object returnVal = null;
        try 
        {
            sessionFactory = MyFactory.getSessionFactory();
            session = sessionFactory.openSession();
            Transaction tx = session.beginTransaction();
            returnVal = session.merge(o);
            tx.commit();

        }
        catch (Exception e)
        {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
        finally
        {
            if(session!=null)
                session.close();
        }
        return returnVal;
    }

Teacher t1 = DataRetrieveModule.getTeacher(id1);
Teacher t2 = DataRetrieveModule.getTeacher(id2);

t1= DataInsertionModule.merge(t1);
t2= DataInsertionModule.merge(t2);

したがって、get-methodが返したものを、他の教師のget呼び出しによってロードされたはずのメソッドとマージすると、機能するはずだと思いました。(ここのように:http://www.stevideter.com/2008/12/07/saveorupdate-versus-merge-in-hibernate/)しかし、そうではありません:(

同じスーパークラスのオブジェクト(Objectまたは私のEntityクラス)が同じIDを持っていることが原因である可能性がありますか?

私を助けてください!

4

1 に答える 1

4

このエラーにつながる可能性のある状況の 1 つは、教師 1 と教師 2 の ID が同じ場合です。各 get の間にセッションを閉じると、それらは分離され、データベース内の同じ行を表す 2 つの異なるオブジェクトをロードすることになります (それらは同じ主キーを持っています)。保存されている SchoolClass を介してセッションにアクセスすると、Hibernate はデータベース内の同じ行を表す 2 つの異なるオブジェクトを認識し、どちらがデータベースに永続化する正しい状態を表しているかを認識しません。

ここに当てはまるかどうかはわかりませんが、デバッガーを実行して、teacher1 と teacher2 によって参照されるオブジェクトの状態を確認する必要があります。

于 2013-02-08T19:39:02.720 に答える