2012-04-15 8 views
6

私はここで紛失しています。おそらく、私のHibernateの専門知識は他の領域よりも弱いので、おそらく明らかです。Hibernateは既存のデータを移行するために埋め込み可能なクラスをスワップします

レガシーコードでは、ハイバーネート@EntityクラスFooがあります。その特性の一つはこれです:

private OldBar bar = new OldBar(); 

OldBarは単一の列、foobarを使用しています@Embeddableクラスです:

@Embeddable 
public class OldBar { 

    private String fooBar; 

    @Column(length = 10, nullable = false) 
    private String getFooBar() { 
    return fooBar; 
    } 

    @SuppressWarnings("unused") 
    private void setFooBar(String fooBar) { 
    this.fooBar = fooBar; 
    } 
} 

元の問題は、私はOldBar.fooBarで何かをするために必要なことですが、元のデザインには制限があり、このフィールドをプライベートにしてサブクラス化するのを防ぎましたので、もう1つのクラスを置き換えてプライベートフィールドにアクセスするために、別のクラス全体を作成する必要がありました(NewBar)。

private NewBar bar = new NewBar(); 

私はfoobar列内の既存のデータを持っているので、これをやってみたかった、と私はNewBarEmbeddableであり、同じ@Column指定を持っているので、私はクラスFooでフィールドをスワップアウトだけのことができると考えました私はこのデータをOldBarの代わりにNewBarと透過的に使いたいと思っていました。

トレースログ私は、コンストラクタが呼び出されたときに期待通りに、NewBar()のデフォルトバージョンでFoo()が作成されていることを確認しました。しかし、タイムコードはFoo.getBar()と呼ばれ、何らかの理由でbarnullです!私は何らかの理由でHibernateがnullに設定していると仮定していますが、foobar列からデータを読み込み、NewBarのインスタンスを作成するのはなぜですか? OldBarNewBarの代わりに入れても、なぜそれが再び動作するのですか?確かに、データベースには、@Embeddableクラスのどれがクラスにマッピングされているかについての情報はありません。

更新:これは見知らぬ人と見知らぬ人になります。時々私はコードを一晩中受けさせ、翌日には動作します!それとも、翌日にはうまくいかない!ちょうど今は動作しませんでした(つまり、foobarプロパティはデータベースの値ではなくnullに設定されていました)ので、クラスExactCopyOfOldBarを作成してOldBarの場所に配置してください。それはうまくいった!だから私はNewBarに戻って---私の一時的な変更を元に戻すだけです。これまでになかった時には、それはまだ機能しました! Hibernateが値をシリアライズし、データベースから取得しないキャッシュがありますか?これは非常に奇妙です。

更新:今や私はNewBarをまったく動作させることができなくなりました。私はOtherBarを作成します。これは基本的にNewBarと同じですが、別の名前が付いています。プラグインして正しく動作し、正しく埋め込まれた文字列を読み込みます。私はNewBarに戻って、nullをもう一度得る。何が起こっている?

Fooが十分に単純であり、 net.databinder.auth.hib.AuthDataApplication.getUser(String username)によってロードされていること

注:私はFoo(ユーザ)の表は、正しいデータを持つ単一の行を有することが何度も何度も検証してきた

return (DataUser) Databinder.getHibernateSession().createCriteria(getUserClass()) 
    .add(Restrictions.eq("username", username)).uniqueResult(); 

と最も重要なのは、foobarフィールドにデータがあることです。なぜHibernateは私にnullfoobarフィールドのFooを返すのですか? NewBarからOtherBarに切り替えると、もう一度動作を開始するのはなぜですか?私はそれを一晩中放置した後、なぜ終日働いてから仕事を止めますか?

+0

私はこれが本当だと仮定していますが、あなたはそれを言っていません: 'Foo.bar'は' @ Embedded'とマークされていますか? –

+0

@Tim Pote:実際は、奇妙なことに、元の(動作している)レガシーコードでは、@埋め込みとしてマークされていませんでした。 'OldBar'を' NewBar'に変更したときに '@ Embedded'の有無にかかわらず試してみましたが、それは違いはありませんでした。 –

+0

@Tim Pote:私はHibernate [documentation](http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html_single/)から、 "もしプロパティの型@Embeddableとしてアノテートされていて、@Embeddedとしてマップされているので、技術的に '@ Embedded'部分はオプションです。 –

答えて

1

これは答えかもしれません。私はそれが実際に問題を解決するかどうかを確認するために数日間待たなければならないでしょう。実際には2つの部分があります。

最初に、完全な開示のために、私のNewBarクラスは実際にはAbstractBarのサブクラスでした。私は最終的に異なる種類の埋め込み可能なバーを持っていたので、AbstractBarレベルにはNewBarレベルではなく@Embeddableを配置し、プライベートfoobarフィールドはAbstractBarレベルに配置しました。面白いことは、これは時間のいくつかの作業です。そして、私が言及したように、時々私は翌日に戻り、Hibernateはfoobarフィールドをロードしません。私はそれがいつも働いていなかったのか、それともいつも働いていなかった理由を理解していません。私は、問題の一つのソースを排除するように、この階層を取り除くしようとしたとき、Hibernateはそれがだった見ていなかったので、

第二に、私は、AbstractBarNewBarを融合したがAbstractBarからNewBarまで@Embeddableを持参するのを忘れ埋め込み可能なクラスであり、@Embeddable指定なしでNewBarフィールドに文字列を読み込む方法がわかりませんでした。このため、OtherBar@Embeddable注釈付き)は機能しましたが、NewBar@Embeddable注釈なし)は機能しませんでした。これほど私は理解しています。なぜHibernateは、フィールドをロードする方法が分からないと私に警告しなかったのですが、わかりません。

要約すると、@Embeddableアノテーションをクラスから外してしまった場合、Hibernateは埋め込み可能フィールドをロードしません。元の問題に関しては、クラス階層でそれを使用しようとすると、@Embeddableが不安定であると推測できます。また、埋め込み可能クラス内のすべての埋め込み可能なフィールドを1つのレベルに保つのが最良です。私はそれが問題だと思います。明日もそれが続くのかどうかはわかります。

関連する問題