2011-12-09 13 views
1

私はHibernate 3.3.1を使用しています。
私はdbテーブルを持っています(2フィールド:idname)。 Hibernateを使用してこのテーブルのクラスを作成しました。私はsession.saveorUpdateを使用してそれらを保存したいし、それがフォームDBをロードしたALL行を保存し、変更を行った後Hibernateは不要なクエリを生成します

@Entity 
@Table(name = "table1") 
public class QTable1 implements Serializable { 

    public QTable1() { 
    } 

    @Id 
    @Column(name = "id") 
    @GeneratedValue(strategy = GenerationType.AUTO) //<- modification: to comment this line 
    private Long id; 

    public Long getId() { 
     return id; 
    } 

    public void setId(Long id) { 
     this.id = id; 
    } 

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

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

} 

。彼らは変更されませんでした場合でも:

update table1 set name='a' where id=1 
update table1 set name='b' where id=2 
update table1 set name='cc' where id=3 // only this row changed 

コードを、エンティティの変更:

final QTable1 item = (QTable1) listTable1.getSelectedValue(); 
if (item != null) { 
    item.setName(table1Name.getText()); 
} 

トランザクションコード:

final Session session = Commons.getSessionFactory().openSession(); 
session.beginTransaction(); 
for (Object o : pool.getTable1List().toArray()) { 
    final QTable1 item = (QTable1) o; 
    session.saveOrUpdate(item); 
} 
session.getTransaction().commit(); 

は、なぜそれがすべてのデータを保存しますか?私はIDの実装を変更した場合

@GeneratedValue(strategy=GenerationType.AUTO)を削除):

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

それだけで、影響を受けた行を保存します。それは私が期待していることです。しかし、@GeneratedValueを付けないと、テーブルに新しい行を追加しようとすると、手動でidを指定する必要があります。

デバッグ中に私は@GeneratedValueのセッションPersistanceContextに自分のエンティティを持っていないので、entitySnapshotsByKeyでエンティティが新規であり、dbにフラッシュする必要があると見なします。

この問題を解決するにはどうすればよいですか?

UPDATE:私たちは@GeneratedValueアノテーションを使用している場合

session.saveOrUpdate(item)だけupdateまたはinsertクエリを生成します。 TABLE1のため しかし、我々はない使用に@GeneratedValue注釈を行う場合session.saveOrUpdate(item) 1を生成)selectは、オブジェクトが等しいか、我々はupdateまたはinsertクエリを生成する必要があるかどうかを判断しませ 3)場合 2)を比較照会します。

今、なぜ@GeneratedValueが値の照合を妨げるのか理解できません。 まだ私はなぜそれがメモリを(entitySnapshotsByKey)選択された行のコピーを持っている場合、selectクエリを理解していない。

しかし私はちょうど良い私に合うsolvationを見つけた。 私が必要とするのはsession.saveOrUpdate(item)session.merge(item)に置き換えることだけです。 selectクエリが作成され、値が比較されることが隔離されます(@GeneratedValueを使用するかどうか)。唯一の欠点は潜在的な多数のクエリです。

ありがとうございます。 selectクエリを生成しないように助けてくれたらうれしいです。

+0

コードの一部のみを表示しています。残りのQTable1クラス、エンティティを変更するコード、およびトランザクション構成を表示できますか? –

答えて

0

これは予期され、文書化された動作です。 saveOrUpdateは、(ID付きの)デタッチエンティティ(IDなし)を取り出し、デタッチされている場合は更新し、一時的な場合はセーブします。

saveOrUpdateフィールドが変更されているかどうかはわかりません。エンティティを取り、それをデータベースに書き込むだけです。

mergeを使用して、データベースから特定のIDを持つエンティティを取得し、分離したエンティティからすべてのフィールドを添付されたエンティティにコピーできます(何かがある場合はフラッシュ時にエンティティをデータベースに書き込みます)。かわった)。しかし、これはデータベースをフェッチし、新しい状態を古いものと比較できるようにselectを必要とします。

+0

私が理解するところでは、問題は 'saveOrUpdate'自体を使うことではありませんが、キーが生成されるという事実は' saveOrUpdate'が動作する方法を変更します。 – ewernli

+0

JB Nizet、 'saveOrUpdate'はGeneratedValueを使わないと' merge'のように動作します。どうして? – Malex

0

下位3番目のバージョンのhibernateの動作が変更されました - 読み込まれたエンティティを明示的に保存する必要はありません(もちろん、適切なドキュメントなし - これは変更されたと判断した場合、 。保存されていない値の設定で再生することもできます。

永続エンティティの保存を防止する場合は、セッションからデタッチする必要があります。

関連する問題