1

Hibernate と LazyInitializationException に問題があります。検索して多くの回答を見つけましたが、それらを使用して問題を解決することはできません。Hibernate は初めてだと言わざるを得ないからです。

エラーが発生した場合は、JUnit テストを実行します。

@Test
public void testAddPerson() {
    Set<Person> persons = service.getAllPersons();

    // create new person
    Person person = new Person();
    person.setEmail("john@doe.com");
    Project testProject = serviceProj.findProjectById(1);

    HashSet<Project> lister = new HashSet<Project>();
    lister.add(testProject);
    person.setProjects(lister);
    service.addPerson(person);

    testProject.getPersons().add(person);
    ...
}

最後に表示された行:

testProject.getPersons().add(person);

このエラーをスローします:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.doe.john.domain.Project.persons, no session or session was closed

Person と Project は双方向の n:m:

Person.java :

@ManyToMany(mappedBy="persons")
private Set<Project> projects = new HashSet<Project>();

Project.java :

@ManyToMany
@JoinTable(name = "Project_Person",
    joinColumns = {@JoinColumn(name="project_id", referencedColumnName="id")},
    inverseJoinColumns = {@JoinColumn(name="person_id", referencedColumnName="id")}
)
private Set<Person> persons = new HashSet<Person>();

だから問題は何ですか?

4

4 に答える 4

1

コードをトランザクション内に配置します-これで問題が解決します

于 2010-10-12T14:03:05.963 に答える
1

問題は、デフォルトでコレクションが遅延ロードされることです。これは、アクセスされるまでデータベースから実際にロードされないことを意味します。それをロードするには、アクティブなセッション/トランザクションが必要です。

簡単な方法は、コレクションがすぐに読み込まれるようにするFethType.EAGERに変更することです。

- アップデート -

私は最近まったく同じ問題を抱えていて、この種のことを処理するために実際のサービスを変更することになりました。ProjectServiceクラスでaddPersonメソッドを宣言します。

public void addPersonTo(Project project, Person person)
{
  project = em.merge(project); //EntityManager, not sure what you are using but you get the idea hopefully
  project.addPerson(person);
}
于 2010-10-12T12:36:59.773 に答える
0

やってみませんか

person.getProjects().Add(testProject)

それ以外の

HashSet<Project> lister = new HashSet<Project>();
lister.add(testProject);
person.setProjects(lister);

休止状態のマネージドコレクションを吹き飛ばしてしまうため、これを行う必要があります。

于 2010-10-12T12:38:54.950 に答える
0

休止状態の参照から:

デフォルトでは、Hibernate3 はコレクションに対して遅延選択フェッチを使用し、単一値の関連付けに対して遅延プロキシフェッチを使用します。これらのデフォルトは、ほとんどのアプリケーションのほとんどの関連付けに適しています。

hibernate.default_batch_fetch_size を設定すると、Hibernate は遅延フェッチにバッチ フェッチ最適化を使用します。この最適化は、より詳細なレベルで有効にすることもできます。

開いている Hibernate セッションのコンテキスト外で遅延関連付けにアクセスすると、例外が発生することに注意してください。例えば:

s = sessions.openSession();
Transaction tx = s.beginTransaction();

User u = (User) s.createQuery("from User u where u.name=:userName")
.setString("userName", userName).uniqueResult();
Map permissions = u.getPermissions();

tx.commit();
s.close();

Integer accessLevel = (Integer) permissions.get("accounts");  // Error!

セッションが閉じられたときに権限コレクションが初期化されていないため、コレクションはその状態をロードできません。Hibernate は、デタッチされたオブジェクトの遅延初期化をサポートしていません。これは、コレクションから読み取るコードをトランザクションがコミットされる直前に移動することで修正できます。

または、関連付けマッピングに lazy="false" を指定することで、非遅延コレクションまたは関連付けを使用できます。ただし、ほとんどすべてのコレクションと関連付けに遅延初期化を使用することを意図しています。オブジェクト モデルで非遅延アソシエーションを定義しすぎると、Hibernate はすべてのトランザクションでデータベース全体をメモリにフェッチします。

一方、特定のトランザクションでの選択フェッチの代わりに、本質的に非遅延の結合フェッチを使用できます。次に、フェッチ戦略をカスタマイズする方法について説明します。Hibernate3 では、フェッチ戦略を選択するメカニズムは、単一値の関連付けとコレクションで同じです。

そのため、コレクションにアクセスした後はセッションを閉じる必要があります!

それ以外の :

service.addPerson(person);

testProject.getPersons().add(person);

私はあなたが持っているべきだと思います:

testProject.getPersons().add(person);
service.addPerson(person);
于 2010-10-12T12:43:19.357 に答える