Part5 - Serialized Fields

(3) 2024-04-29 10:23

Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说Part5 - Serialized Fields,希望能够帮助你!!!。
你好,欢迎来到第5part的“JDO/JPA Snippets That Work”,今天我们将讨论的是...

Serialized Fields

假设你有个model objects拥有一个非native datastore的(例如String或者Date)同时也不是一个有主,一对一关系的model object的字段。通常你可以在一条记录里用一个Embedded class包含住些record来保存这个字段的子字段。但如果Embedded class不够用的时候呢?

这时就可以用Serialized Fields了。

用jdo和jpa可以保存任何实现了java.io.Serializable接口的single prperty。

为了我们的例子程序,我们建立一个Person,一个ContactProfiles,一个ContactProfile, 和一个PhoneNumber的模型。一个Person只用一个ContactProfiles实例,而,一个ContactProfiles有多个ContactProfile实例,同时,一个ContactProfile有多个PhoneNumber实例。

现在我们程序要求是这样:当我们从datastore里retrieve一个Person时,需要同时load入这个Person的ContactProfiles.我们首先先用jdo或jpa来定义ContactProfiles,ContactProfile和PhoneNumber类先。


public static class ContactProfiles implements Serializable {
private final List<ContactProfile> profiles;
public ContactProfiles(List<ContactProfile> profiles) {
this.profiles = profiles;
}
public List<ContactProfile> get() {
return profiles;
}
}

public class ContactProfile implements Serializable {
private String profileName;
private List<PhoneNumber> phoneNumbers;
// getters and setters
}

public class PhoneNumber implements Serializable {
private String type;
private String number;
// getters and setters
}

JPA方式定义的Person类如下:

@Entity 
public class Person {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Key id;
@Lob
private ContactProfiles contactProfiles;
// getters and setters
}

JDO方式定义的Person类如下:

@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = 
"true")
public class Person {
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key id;
@Persistent(serialized = "true")
private ContactProfiles contactProfiles;
// getters and setters
}

在这个例子里面,App Engine实现将Person.contactProfiles字段转换为一个实现了标准Java

serialization接口的com.google.appengine.api.datastore.Blobusing类。

这个Blob将以single property的形式存储在Person Entity里面。当你fetch一个Person的时候,相应的Blob将会经过一个独立的datastore rpc请求被反序列化,你将得到一个ContactProfiles实例和全部他关联的子对象。

当用这种做法时,有一些缺点你是应该意识到的。

第一,虽然你的应用知道ContactProfiles的结构,但datastroe并不知道,这导致你不能过滤或排序ContactProfile和PhoneNumber.第二,所有已知java serialization存在的问题都适用在这里。当你改进你的Serializable classes的时候,请必须考虑向后兼容。第三,你可能在观察ContactProfiles这个类的时候已经发现,为什么我们要用一个这么麻烦的ContactProfiles类而不直接用一个List<ContactProfile>呢?其原因就是update一个serialized field并不是好像update其他字段类型那么简单。DataNucleus并没有办法“看”得见你修改了serialized field,这就意味着他不会更新数据到datastore。然而,DataNucleus可以看到顶层的serialized field的改变。给Person类一个ContactProfiles一个引用可以便利我们去修改ConactProfiles而DataNucles又保证能意识到。

public void addContactProfile(Person p, ContactProfile cp) { 
// update our serialized field
p.getContactProfiles().get().add(cp);
// give the person a new ContactProfiles reference so the update is
detected
p.setContactProfiles(new ContactProfiles(p.getContactProfiles().get()));
}

最后一行我们设回一个新的ContactProfiles实例给Person是关键,同时也容易忘记的,所以请小心!如果你忘记这一步,你的更新将被忽略。

尽管我列出了以上的不足,但Serialized fields是一个保存structured data到一个记录到containing Entity的好方法。只要你不需要过滤和排序serialized fields,同时你记得这个特别的更新数据的要求,在某些时候serialized fields也无疑是一个方便的方法。

以下是原文

Hello hello and welcome to Episode 5 of JDO/JPA Snippets That Work. Today

we'll be discussing....

Serialized Fields

Suppose one of your model objects has a field that isn't a native datastore

type like String or Date and isn't another model object, like the child of

an owned OneToOne relationship. Oftentimes you can use an Embedded

class<http://code.google.com/appengine/docs/java/datastore/dataclasses.html...>to

store that field's sub-fields in the same record as the containing

record, but what if an Embedded class isn't sufficient? This is where

Serialized Fields come in. With JDO and JPA it's possible to store any

class that implements java.io.Serializable in a single property.

For our example lets model Person, ContactProfiles, ContactProfile, and

PhoneNumber. A Person has exactly one ContactProfiles instance, a

ContactProfiles has some number of ContactProfile instances, and a

ContactProfile has some number of PhoneNumber instances. Our application is

such that when we retrieve a Person from the datastore it always makes sense

to load their ContactProfiles as well. We'll define ContactProfiles,

ContactProfile, and PhoneNumber first since they're the same whether we're

using JPA or JDO:

public static class ContactProfiles implements Serializable { 
private final List<ContactProfile> profiles;
public ContactProfiles(List<ContactProfile> profiles) {
this.profiles = profiles;
}
public List<ContactProfile> get() {
return profiles;
}
}

public class ContactProfile implements Serializable {
private String profileName;
private List<PhoneNumber> phoneNumbers;
// getters and setters
}

public class PhoneNumber implements Serializable {
private String type;
private String number;
// getters and setters
}

The JPA Person definition:

@Entity 
public class Person {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Key id;
@Lob
private ContactProfiles contactProfiles;
// getters and setters
}

The JDO Person definition:

@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = 
"true")
public class Person {
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key id;
@Persistent(serialized = "true")
private ContactProfiles contactProfiles;
// getters and setters
}

In this example the App Engine JDO/JPA implementation converts the

Person.contactProfiles field into a

com.google.appengine.api.datastore.Blobusing standard Java

serialization. This Blob is then stored as a single

property on the Person Entity. When you fetch a Person the corresponding

Entity is retrieved and the Blob is deserialized in just a single datastore

rpc, leaving you with a ContactProfiles instance and all its associated

sub-objects.

There are a few drawbacks to this approach that you should be aware of.

First, even though your application understands the structure of the bytes

that make up the ContactProfiles, the datastore does not. As a result you

can't filter or sort on any of the properties of ContactProfile or

PhoneNumber. Second, all the known gotchas associated with Java

serialization apply here. If you evolve your Serializable classes make sure

you do it in a backwards compatible way! Third, you might be looking at the

definition of the ContactProfiles class and thinking "Why are we bothering

with a ContactProfiles class when Person could just store

List<ContactProfile>?" The reason is that updating a serialized field is

not as simple as updating other types of fields, and this extra layer of

indirection makes things a bit easier. DataNucleus has no way of "seeing"

the changes you make to the internal values of a serialized field, and as a

result it doesn't know when it needs to flush changes to these fields to the

datastore. However, DataNucleus *can* see when the top-level serialized

field reference changes. Giving Person a reference to a ContactProfiles

object makes it easy for us to change ContactProfiles in a way that

DataNucleus is guaranteed to recognize:

public void addContactProfile(Person p, ContactProfile cp) { 
// update our serialized field
p.getContactProfiles().get().add(cp);
// give the person a new ContactProfiles reference so the update is
detected
p.setContactProfiles(new ContactProfiles(p.getContactProfiles().get()));
}

The last line where we set a new ContactProfiles instace back on the Person

is the key and it's easy to miss, so be careful! If you forget this step

your updates will be ignored and you will be sad.

Despite the limitations I've listed, Serialized fields are a good way to

store structured data inside the record of a containing Entity. As long as

you can get by without filtering or sorting on this data and you remember

that it has special update requirements, serialized fields will almost

certainly come in handy at some point.

Until next time,

Max

转载自:[url]http://groups.google.com/group/google-appengine-java/browse_thread/thread/747ceed8396c0ed8#[/url]

说明:上面的中文翻译是我用自己能理解的方式翻译出来的,并不是逐字翻译,只作为自己参考用,并不十分精确。

其实个人觉得这个做法必须用到的地方可能不多哦。今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。

上一篇

已是最后文章

下一篇

已是最新文章

发表回复