5

hibernate @version と ManyToOne マッピングの関係は何ですか。

Department と Employee という 2 つのテーブルがあるとします。Deparment がマスター テーブルで、Employee がディテール テーブルです。Employee テーブルでは、 departmentID が外部キーとして参照されます。

ここに私のクラスがあります

Public class Department {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long ID;
    @Version
    private Long version;

    //Getters and Setters

}

public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long ID;
    @Version
    private Long version;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "departmentID" )
    private Department department;

}

また、Spring がセッションを処理します。したがって、あるページで特定の部門が取得され、HTTP セッションに保存されているとします。

今別のページで、私は次のことをしようとしています

Employee emp = new Employee();
emp.setName('Test')
emp.setDepartment(dept) // already stored in the HTTP session variable
service.save(emp)

今、次の例外が発生しています

org.springframework.dao.InvalidDataAccessApiUsageException: object references an unsaved transient instance - save the transient instance before flushing: 

そして、次のように1つの変更を加えるだけでエラーが発生します

Employee emp = new Employee();
emp.setName('Test')
dept.setVersion(0);
emp.setDepartment(dept) // already stored in the HTTP session variable
service.save(emp)

私の春の設定

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-3.0.xsd
       http://www.springframework.org/schema/tx
               http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

<bean id="transactionManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

<!-- Container Configuration: The IOC container configuration xml file is 
    shown below,The container has the <context:component-scan> element and <context:annotation-config/> 
    <context:annotation-config/> used to intimate the beans of this IOC container 
    are annotation supported. By pass the base path of the beans as the value 
    of the base-package attribute of context:component-scan element, we can detect 
    the beans and registering their bean definitions automatically without lots 
    of overhead. The value of base-package attribute is fully qualified package 
    name of the bean classes. We can pass more than one package names by comma 
    separated -->

<context:annotation-config />
<context:component-scan base-package="com.product.business" />

<tx:annotation-driven transaction-manager="transactionManager" />

<!-- This will ensure that hibernate or jpa exceptions are automatically 
    translated into Spring's generic DataAccessException hierarchy for those 
    classes annotated with Repository -->

<bean
    class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

<bean id="CRUDService" class="com.product.business.service.CRUDServiceImpl" />
<bean id="AuthService" class="com.product.business.service.AuthServiceImpl" />

サービスの実装

package com.product.business.service;

import java.io.Serializable;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.product.business.dao.CRUDDao;

@Service
public class CRUDServiceImpl implements CRUDService {

    @Autowired
    private CRUDDao CRUDDao;

    @Transactional(readOnly = true)
    public <T> List<T> getAll(Class<T> klass) {
        return CRUDDao.getAll(klass);
    }

    @Transactional
    public <T> void Save(T klass) throws DataAccessException {
        CRUDDao.Save(klass);
    }

    @Transactional
    public <T> void delete(T klass) throws DataAccessException {
        CRUDDao.delete(klass);
    }

    @Transactional
    public <T> T GetUniqueEntityByNamedQuery(String query, Object... params) {
        return CRUDDao.GetUniqueEntityByNamedQuery(query, params);
    }

    @Transactional
    public <T> List<T> GetListByNamedQuery(String query, Object... params) {
        return CRUDDao.GetListByNamedQuery(query, params);
    }

    @Override
    @Transactional(readOnly = true)
    public <T> Long getQueryCount(String query, Object... params) {
        return CRUDDao.getQueryCount(query, params);
    }

    @Override
    @Transactional(readOnly = true)
    public <T> T findByPrimaryKey(Class<T> klass, Serializable id) {
         return CRUDDao.findByPrimaryKey(klass, id);
    }

}
4

3 に答える 3

4

Departmentを保存する前に、まず を保存する必要がありますEmployee

service.save(dept);
service.save(emp);

あなたのコメントに応じて更新:

Employee を Department に関連付けるには、存在する Department が必要です。あなたのデータベースでは、従業員は部門への FK を持っているので、Hibernate が不平を言っているのは、存在しない部門で従業員を保存しようとしているということです。したがって、次のオプションがあります。

  1. 部門が新しい部門である場合は、従業員を保存する前に最初に部門を保存する必要があります。
  2. entityManager.find(id, Department.class) などのクエリを使用して、既に保存されている部門を検索し、そのオブジェクトを Employee オブジェクトで使用します。
  3. Employee で Deparment との関係を @Cascadeとしてマークします。
于 2013-09-24T13:53:41.537 に答える
0

これは古い投稿であることは知っていますが、おそらくこれは他の人に役立つでしょう。

これは、Hibernate を JPA 実装として使用していることを前提としています。

Department はセッションに保存されているため、切り離されていると言っても過言ではありません。

Department インスタンスを変更していないため、この場合の最適なルートは次のとおりです。

Employee emp = new Employee();
emp.setName("Test");
emp.setDepartment(em.getReference(Department.class, dept.getID());
service.save(emp);

ここで Hibernate のドキュメントを参照してください: Entity Manager - Loading an Object

EntityNotFoundException が発生した場合は、Department を最初に取得したコードが、Department を取得するトランザクション内で少なくとも 1 つのメソッドを呼び出していることを確認してください。

于 2014-12-04T16:57:30.597 に答える
0

あなたの主な問題は、カスケードではなくフェッチです。

次の投稿を参照してください: Java Persistence API の FetchType LAZY と EAGER の違いは?

@ManyToOne(fetch = FetchType.EAGER)

そうしないと、前述のようにセッションが閉じられ、オブジェクトが失われます。Eager fetching により、開いたままになります。

于 2013-12-07T14:40:18.447 に答える