使用FlexJSON反序列化多对一关系

时间:2013-01-25 14:29:43

标签: java spring deserialization flexjson

我正在为我的Web应用程序添加RESTful支持(使用Spring),因此我可以执行这样的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:object引用未保存的瞬态实例 - 在刷新之前保存瞬态实例

有什么想法?

奥古斯丁

更新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需要额外的查询来询问类别?
  3. 你的想法?

1 个答案:

答案 0 :(得分:1)

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

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

What is the proper way to re-attach detached objects in Hibernate?

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