使用FlexJSON反序列化多对一关系 [英] Deserializing a many-to-one relation with FlexJSON

查看:95
本文介绍了使用FlexJSON反序列化多对一关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为我的Web应用程序添加RESTful支持(使用Spring),因此我可以执行如下CRUD操作: 阅读有关参与者的信息(JSONSerialize):

I am adding RESTful support to my web application (with Spring) so I can do CRUD operations like this: Read info about a participant (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)

Or create a new participant (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对象的所有字段来创建参与者,我只需要知道唯一的代码即可.对于序列化,我可以使用:

But the thing is, I don't need to know all the fields of the mainFunction object to create a participant I just need to know the code which is unique. For the serialization I can use:

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

然后我得到以下json:

And I get the following 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
}

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

For the deserialization I don't know. The requirement seems pretty common so I wanted to ask in the forum. Any ideas?

总而言之,有一个父对象带有一个对子对象的引用(多对一).如果我向父母提供孩子的所有信息,则一切正常.但是,稍等片刻,拥有孩子的ID应该足以保护父母.我尝试仅使用孩子的ID保存父对象,然后出现此异常:

To sum up, there is a parent object with a reference (many-to-one) to a child object. If I provide the parent with all the information of the child, everything works fine. But hold on a second, with the ID of the child should be enough to safe the parent. I try to save the parent with just the ID of the child and then I get this exception:

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

org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing

有什么想法吗?

奥古斯丁

2013年1月27日更新:问题似乎来自Hibernate.假设我们有产品和类别.该关系是产品具有对类别的引用(多对一关系).给定一个先前保存在数据库中的类别.您不能创建产品,而仅提供类别的ID即可创建产品.即使Hibernate不会查看用于创建产品的版本,您也将需要该版本.参见下文:

UPDATE 27-Jan-2013: It looks like the issue comes from Hibernate. Let say we have products and categories. The relation is that products have a reference to a category (many-to-one relation). Given a category previously saved in a database. You cannot create a product and just give the ID of the category to create the product. You will need the version as well even though Hibernate won't look at the version to create the product. See below:

/*
 * 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将对数据库进行额外的查询以询问该类别.

That will fail. But if you uncomment the version of the category, the product will be created. Also, Hibernate will do an extra query to the database asking for that category.

这里有两个问题:

  1. 为什么Hibernate最终不需要它,为什么还需要该字段版本?
  2. 为什么Hibernate会额外查询该类别?

您的想法?

推荐答案

在处理从JSON或外部表示形式传入的对象时,从Hibernate的角度来看,您始终在处理分离的对象.

When you are working with objects that are coming in from JSON or external representations you are always working with detached objects from Hibernate's perspective.

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

It's been a while since I've done any serious hibernate, but if you are creating an object Hibernate doesn't know about you have to tell it by re-attaching the object with the session. It will then pull the information it needs from the database to associate it with the session, including any versioning information. This is referred to as a detached object because it was created outside of the Hibernate session, and Hibernate doesn't know if this object is a new object or an object that exists in the DB. You can re-attach objects with session.merge(someObject). You only need to reattach the parent btw. For a better explanation:

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

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

The version information is used for optimistic locking. So in a multi-client environment it's possible two request could modify the same object in the DB and it's your job as the programmer to order those modifications and make sure one doesn't overwrite the other. Optimistic locking is one way to do this where objects are given versions when someone modifies the object the version is incremented. However, before a new version is saved you have to check and make sure the object being given to the DB is the same version as the one stored in the DB. That makes sure that what mods you're about to save were done on the latest version stored in the DB. That means you can't overwrite the object with an old version of that object. Without that version information Hibernate can't performing optimistic locking.

这篇关于使用FlexJSON反序列化多对一关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆