Hibernate Session Problemi: Illegal attempt to associate a collection with two open sessions

BTSoru.com projesini modellerken aşağıdaki hata ile karşılaştım:

org.hibernate.HibernateException: Illegal attempt to associate a collection with two open sessions
at bt.btsoru.application.manager.question.facade.QuestionManagerImpl.addQuestion(QuestionManagerImpl.java:57)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

Hatanın oluşmasını sağlayan kod bölümü şu şekilde:

// Soruyu ekleme bölümü
BTUser user = new BTUser();
user.setId(WebSession.get().getUser().getId());
getQuestion().setUser(WebSession.get().getUser());

QuestionManagerResult result = qManager.addQuestion(getQuestion());

Kod 1.1

Birinci satırda yer alan BTUser bir Hibernate nesnesi. BTUser ile bir kullanıcıyı modelliyorum. UML diagramı aşağıda yer almaktadır:

Sistem bünyesinde her kullanıcının sıfır ya da birden fazla sorusu olabilir. Sorulan her soru sadece bir kullanıcıya aittir. BTUser gibi BTQuestion sınıfı da bir Hibernate nesnesi, yani ihtiva ettiği veriler bilgilbankasında saklanabilmekte.

Kod 1.1 de yer alan kodun yedinci satırında qManager.addQuestion() metodu ile yeni bir soruyu (BTQuestion nesnesini) bilgibankasına ekliyorum. BTQuestion nesnesinin ihtiva ettiği verileri bir form üzerinden kullanıcı daha önce girdi. Gerekli validasyon işlemlerini daha önce gerçekleştirerek, BTQuestion nesnesini, yani kullanıcının sisteme eklemek istediği soruyu bilgibankasına ekliyorum.

BTUser ile BTQuestion arasındaki ilişkiyi sağlamak için aşağıdaki şekilde BTQuestion bünyesinde bir ManyToOne ilişkisini oluşturuyorum. Bu şekilde BTQuestion nesnesi bir kullanıcıya atanmış olacaktır.


@ManyToOne(cascade=CascadeType.ALL,fetch=FetchType.LAZY)
@JoinTable(
name="btsoru_user_questions",
joinColumns = { @JoinColumn( name="question_id", unique = false) },
inverseJoinColumns = @JoinColumn( name="user_id", unique = false)
)
private BTUser user;

Kod 1.2

@JoinTable anotasyonu ile kullanıcı ile sahip olduğu soruları ilişkilendirmek için yeni bir bilgibankası tablosu oluşturuyorum (btsoru_user_question). Bu tablo bünyesinde kullanıcının sahip olduğu tekil numara (user_id) ve soru nesnesinin tekil numarası (question_id) yer almaktadır. Bu şekilde kullanıcı ve soruyu ilişkilendirmiş oluyorum.

Bu konfigurasyonda kod 1.1 altıncı satırda yer alan qManager.addQuestion() metodunu kullandığım taktirde, yukarda bahsettiğim Hibernate problemi oluşuyor. Bunun sebebi şudur: Kod 1.1, üçüncü satırda Hibernate tarafından kontrol edilen bir sınıfdan (BTUser) bir nesne oluşturarak, bu nesneye id değerini atıyorum. Buradaki amacım, bir BTQuestion nesnesini bilgibankasına eklemeden önce bir BTUser nesnesi ile ilişkilendirmek. Bunu getQuestion().setUser(WebSession.get().getUser()); ile gerçekleştiriyorum. Bunu yapmadığın taktirde, bilgibankasına herhangi kullanıcıya ait olmayan bir soru yer alacaktır ve bu istenmeyen bir durumdur. Dördüncü satırda WebSession.get().getUser().getId()); ile kullanıcı id sini session içinde bulunan BTUser nesnesinden ediniyorum. Id değişkenini kullanıcının kimlik numarası olarak düşünebilirsiniz. Bu işlemi gerçekleştirebilmem için kullanıcının soruyu sisteme eklemeden önce isim ve şifresi ile login yapmış olması gerekmektedir. Login işlemi ardından oluşturduğum BTUser nesnesini session içine yerleştiriyorum ve gerekli durumlarda WebSession.get().getUser()); ile bu nesneye, yani login yapmış kullanıcının bilgilerine ulaşıyorum. Sorun da ne yazik ki burada oluşmaktadır. Login işleminin ardından belirli bir id ye sahip bir BTUser nesnesi sistemde (session içinde) mevcuttur. Aynı id ye sahip ikinci bir nesne oluşturulduğu taktirde, Hibernate buna Illegal attempt to associate a collection with two open sessions hata mesaji ile karşı çıkacaktır. Böyle bir konstellasyonda Hibernate kontrolünde bulunan (Hibernate Cache) bir nesneye rakip olacak aynı id yi taşıyan ikinci bir nesne oluşturup kullanmamız mümkün değildir.

Bu sorunu aşmak için BTQuestion bünyesinde bulunan BTUser değişkeninin mapping parametrelerini kod 1.3 deki gibi değiştirmemiz yeterli olacaktır.


@ManyToOne(fetch=FetchType.LAZY)
@JoinTable(
name="btsoru_user_questions",
joinColumns = { @JoinColumn( name="question_id", unique = false) },
inverseJoinColumns = @JoinColumn( name="user_id", unique = false)
)
private BTUser user;

Kod 1.3

@ManyToOne anotasyonundaki cascade=CascadeType.ALL elementini kaldırmamız yeterlidir.


EOF (End of Fun)
Özcan Acar



Püf Noktası kategorisinden son yazılar

Share Button
0.00 avg. rating (0% score) - 0 votes

2 Comments

  • Emre SÜREN

    30 Eylül 2009

    Ozcan Bey;

    Hibernate sorununu zaten kendiniz cozmussuznuz ama benim burada dikkatimi ceken baska birsey var.

    btsoru_user_questions tablosundaki question_id kolonunun unique olmasi gerektigini dusunuyorum.
    @ManyToOne iliski oldugunu belirtmissiniz.

    Iyi calismalar.

  • acar

    01 Ekim 2009

    question_id kolonu unique

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = “id”)
    private Long id;

Bir cevap yazın