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
}

对于反序列化我不知道。这个要求似乎很普遍,所以我想在论坛中提问。有任何想法吗?

总而言之,有一个父对象具有对子对象的引用(多对一)。如果我向父母提供孩子的所有信息,一切正常。但是等一下,孩子的身份证应该足以保护父母的安全。我尝试只用孩子的 ID 保存父母,然后我得到这个异常:

org.hibernate.TransientPropertyValueException:对象引用了一个未保存的瞬态实例 - 在刷新之前保存瞬态实例

有什么想法吗?

奥古斯丁

2013 年 1 月 27 日更新:看起来问题来自 Hibernate。假设我们有产品和类别。关系是产品具有对类别的引用(多对一关系)。给定先前保存在数据库中的类别。您不能创建产品,只需提供类别的 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 将对数据库进行额外的查询以获取该类别。

这里有两个问题:

  1. 为什么 Hibernate 需要字段版本,即使它最终看起来不是它?
  2. 为什么 Hibernate 会额外查询类别?

你的意见?

4

1 回答 1

1

当您处理来自 JSON 或外部表示的对象时,您总是从 Hibernate 的角度处理分离的对象。

我已经有一段时间没有做任何严肃的休眠了,但是如果你正在创建一个对象,休眠不知道你必须通过重新附加会话的对象来告诉它。然后它将从数据库中提取所需的信息以将其与会话相关联,包括任何版本信息。这被称为分离对象,因为它是在 Hibernate 会话之外创建的,并且 Hibernate 不知道该对象是新对象还是数据库中存在的对象。您可以使用 session.merge(someObject) 重新附加对象。您只需要重新附加父 btw。为了更好的解释:

在 Hibernate 中重新附加分离对象的正确方法是什么?

版本信息用于乐观锁定。因此,在多客户端环境中,两个请求可能会修改数据库中的同一个对象,而程序员的工作就是订购这些修改并确保一个不会覆盖另一个。乐观锁定是一种方法,当有人修改对象时,对象会被赋予版本,版本会增加。但是,在保存新版本之前,您必须检查并确保提供给 DB 的对象与存储在 DB 中的对象版本相同。这样可以确保您要保存的模组是在数据库中存储的最新版本上完成的。这意味着您不能用该对象的旧版本覆盖该对象。如果没有该版本信息,Hibernate 将无法执行乐观锁定。

于 2013-01-29T02:12:47.923 回答