2011-09-17 8 views
6

具体的なスーパークラスをそのサブクラスの1つに変更したいと思います。私は以下の例を含めました:Hibernate:ベースクラスのインスタンスをサブクラスに変更する

@Entity 
@Table(name = "employees") 
@Inheritance(strategy = InheritanceType.JOINED) 
public class Employee { 

    @Id 
    @Column(name = "id") 
    private String id; 

    public Employee(String id) { 
     this.id = id; 
    } 
... 
} 

@Entity 
@Table(name = "managers") 
@PrimaryKeyJoinColumn(name = "id", referencedColumnName = "id") 
public class Manager extends Employee { 

    public Manager(String id) { 
     super(id); 
    } 
... 
} 


@Entity 
@Table(name = "history") 
public class History { 
... 
/** 
* 
*/ 
@ManyToOne 
@JoinColumn(name = "employee_id") 
private Employee employee; 
... 
} 

私が扱っている3つのクラスは、従業員、マネージャー、そして履歴です。すべてのマネージャは従業員ですが、すべての従業員がマネージャではありません。すべての従業員(およびマネージャー)には歴史があります。従業員は経営陣に昇進することができます。これが起こると、従業員の履歴は、従業員IDを同じに保つことによって保持する必要があります。これにより、雇用を通じてマネージャーの歴史を簡単に見つけることができます。

プロモーション操作の実装は、データベースの制約によって複雑になります。カスケード操作ですべてのHistoryオブジェクトを削除せずに、古い従業員を削除し、同じIDを持つ新しいマネージャを作成することはできません。許可しないと、私の仕事は簡単になります!

はそれがを追加したり、カスタムSQL操作に頼ることなく、既存の従業員にマネージャー(新しいマネージャー)行を添付することは可能ですか?これが行わ

public void promote(Employee employee) { 
    /* copy over the ID of the employee to the manager. Will not work because employee with ID already exists */ 
    Manager manager = new Manager(employee.getId()); 
    this.entityManager.persist(manager); 
} 

...か...

public void promote(Employee employee) { 
    /* detach the employee then merge. Will not work: fails, again, with a NonUniqueObject Exception */ 
    this.entityManager.detach(employee); 
    Manager manager = new Manager(employee.getId()); 
    this.entityManager.merge(manager); 
} 

はどのように取得することができます。

私は次の成功なしのソリューションを試してみましたか?私は正しいトラックでさえもdetach()merge()

これはHibernate/JPAで可能ですか?

私が困惑しているので、どんなアイデアもこの時点で役立ちます!あなたは間違いなく見始めていないしているとして

  • アーロン

答えて

6

、あなたはここで、風に対して漕ぎます。残念ながら、using inheritance to represent roleという古典的な例があるようです。あなたのオブジェクトモデルが間違っているため、Hibernate - オブジェクト - リレーショナルマッパー - とJava - オブジェクト - オリエンテーションされた言語の両方があなたにこれと戦うつもりです。私はあなたの最善の策は、今すぐリファクタリングとデータの移行でそれを修正することだと思います。最終的な結果は、全員が従業員であり、一部の従業員が1つ以上の部署または他の従業員と何らかの種類の「管理」関係を持っていることです。

+0

この共通OOのflubを扱うので-休止方法を持っていないHibernateはありますか?この問題は、オブジェクトアイデンティティの問題として説明することもできます。私はヒベネイトに、あるトランザクションのために、equals()と== semanticistsを保存しようとすることを忘れて、 !=、equal()にして、サブクラスのINSERTを実行するように指示します。私は、永続性VMの状態がやや矛盾したままになることを理解しています。アプリケーションは実際にはそのために設計されています(キャッシングなどはありません)。他のアイデア? –

+0

@Aaron:マップされたEmployee-> Historyの関係はありますか?そうであれば、マネージャオブジェクトを作成し、古い従業員のすべてのプロパティを新しいマネージャにコピーして、マネージャの履歴に履歴オブジェクトを設定し、従業員の履歴をnullに設定することができます。 EmployeeインスタンスからManagerインスタンスへの履歴。 –

+0

ありがとう!元々、低レベルのhibernate/jpaメソッドの1つがアイデンティティの変更を管理するのに役立つと思っていましたが、それはうまくいかないでしょう。 –

1

私は同様の状況に遭遇しました。データモデルが現実世界のモデルと非常によく似ているため、欠陥のあるデータモデルは責任を負いません。

サブクラスレコードを手動で挿入して、目的の結果を得ることができます。時にはそれが何かを成し遂げるために休止状態の周りに行くために必要なのですので、これは私が回避策として、この場合に何をしたかである:

sessionFactory.getCurrentSession().createSQLQuery(
      "insert into manager (employee_id, rank) " + 
      "values (:employeeId, :rank) ") 
      .setParameter("employeeId", employeeId) 
      .setParameter("rank", rank) 
      .executeUpdate(); 
関連する問題