0

Web アプリケーション (Spring を使用) に RESTful サポートを追加しているので、次のような CRUD 操作を実行できます: 参加者に関する情報を読む (JSONSerialize):

$ curl -i -H "Accept: application/json" http://localhost:8080/dancingwithstars/participant/1
{
    "birthDate": "2013-01-23",
    "code": "JS0001",
    "firstName": "Julia",
    "mainFunction": {
        "code": "AA"
        "name": "Principal Dancer"
    },
    "gender": "F",
    "height": 160.00,
    "id": 1,
    "lastName": "Smith",
    "version": 1,
    "weight": 55.00
}

または、新しい参加者を作成します (JSONDeserialize)

$ curl -i -X POST -H "Content-Type: application/json" -H "Accept: application/json" -d '{"birthDate":"2013-01-15","code":"AT0001","firstName":"Angela","mainFunction":{"code": "AB", "name":"Choreografer"},"gender":"F","height":189.00,"lastName":"Wright","version":0,"weight":76.00}' http://localhost:8080/dancingwithstars/participants

しかし問題は、参加者を作成するために mainFunction オブジェクトのすべてのフィールドを知る必要はありません。唯一のコードを知る必要があるだけです。シリアライゼーションには、次を使用できます。

return new JSONSerializer().include("mainFunction.code").exclude("mainFunction.*").exclude("*.class").transform(new DateTransformer("yyyy-MM-dd"), Date.class).prettyPrint(true).serialize(this);

そして、次のjsonを取得します。

{
    "birthDate": "2013-01-23",
    "code": "JS0001",
    "firstName": "Julia",
    "mainFunction": {
        "code": "AA"
    },
    "gender": "F",
    "height": 160.00,
    "id": 1,
    "lastName": "Smith",
    "version": 1,
    "weight": 55.00
}

デシリアライズについてはわかりません。要件はかなり一般的であるように思われるので、フォーラムで質問したいと思いました。何か案は?

要約すると、子オブジェクトへの参照 (多対 1) を持つ親オブジェクトがあります。親に子供のすべての情報を提供すれば、すべてうまくいきます。しかし、ちょっと待ってください。子供の ID があれば、親を安全に保つのに十分なはずです。子の ID だけで親を保存しようとすると、次の例外が発生します。

org.hibernate.TransientPropertyValueException: オブジェクトが保存されていない一時インスタンスを参照しています - フラッシュする前に一時インスタンスを保存します

何かご意見は?

アグスティン

2013 年 1 月 27 日更新: この問題は Hibernate に起因するようです。製品とカテゴリがあるとします。この関係は、製品がカテゴリへの参照を持っていることです (多対 1 の関係)。以前にデータベースに保存されたカテゴリを指定します。商品を作成することはできず、商品を作成するためにカテゴリの ID を指定するだけです。Hibernate は製品を作成するためにバージョンを確認しませんが、バージョンも必要になります。下記参照:

/*
 * Create one category before the product
 */
Category cat1 = new Category();
cat1.setCode("KIT");
cat1.setName("Kitchen products");
session.save(cat1);
session.flush();
session.clear();
Category cat1db = (Category) session.get(Category.class, cat1.getCode());
logger.info(cat1.toString());
assertNotNull(cat1db.getVersion());

/*
 * Create the product and assign it a category
 */
Product p1 = new Product();
p1.setName("Kettle");
p1.setPrice(4D);
Category c1 = new Category();
c1.setCode("KIT");
//c1.setVersion(new Integer(666));
p1.setCategory(c1);
session.save(p1);
session.flush();
session.clear();
Product p1db = (Product) session.get(Product.class, p1.getId());
logger.info(p1.toString());
assertNotNull(p1db.getId());

それは失敗します。ただし、カテゴリのバージョンのコメントを外すと、製品が作成されます。また、Hibernate はデータベースに対して追加のクエリを実行し、そのカテゴリを要求します。

ここで 2 つの質問:

  1. 最後にそれが見えないのに、Hibernate がフィールド バージョンを必要とするのはなぜですか?
  2. Hibernate がカテゴリを要求する追加のクエリを実行するのはなぜですか?

あなたの考え?

4

1 に答える 1

1

JSON または外部表現から入ってくるオブジェクトを操作する場合、Hibernate の観点からは常に切り離されたオブジェクトを操作します。

本格的な休止状態を行ってからしばらく経ちましたが、Hibernate が知らないオブジェクトを作成している場合は、そのオブジェクトをセッションに再アタッチすることで、それを通知する必要があります。次に、データベースから必要な情報を取得して、バージョン情報など、セッションに関連付けます。これは、Hibernate セッションの外で作成されたものであり、Hibernate はこのオブジェクトが新しいオブジェクトなのか、DB に存在するオブジェクトなのかを認識できないため、切り離されたオブジェクトと呼ばれます。session.merge(someObject) でオブジェクトを再アタッチできます。親を再接続するだけです。より良い説明のために:

Hibernateで切り離されたオブジェクトを再接続する適切な方法は何ですか?

バージョン情報は、楽観的ロックに使用されます。したがって、マルチクライアント環境では、2 つの要求が DB 内の同じオブジェクトを変更する可能性があり、プログラマーとしてのあなたの仕事は、これらの変更を注文し、一方が他方を上書きしないようにすることです。オプティミスティック ロックは、誰かがオブジェクトを変更したときにバージョンがインクリメントされるオブジェクトにバージョンが与えられる、これを行う 1 つの方法です。ただし、新しいバージョンを保存する前に、DB に渡されるオブジェクトが DB に格納されているものと同じバージョンであることを確認する必要があります。これにより、保存しようとしている mod が、DB に保存されている最新バージョンで行われたことを確認できます。つまり、そのオブジェクトの古いバージョンでオブジェクトを上書きすることはできません。そのバージョン情報がなければ、Hibernate は楽観的ロックを実行できません。

于 2013-01-29T02:12:47.923 に答える