2009/05/09

Defining Data Classes

つづきのつづき。気合がなくなってきた。というかどこかにすでにあるんじゃないだろうか。

エンティティグループ周りを理解していないのであやしい。

Defining Data Classes

You can use JDO to store plain Java data objects (sometimes referred to as "Plain Old Java Objects" or "POJOs") in the datastore. Each object that is made persistent with the PersistenceManager becomes an entity in the datastore. You use annotations to tell JDO how to store and recreate instances of your data classes.

素のJavaデータオブジェクト(しばしば"Plain Old Java Objects"または”POJO"として呼ばれます)をDatastoreに保存するためにJDOを使うことができます。 PersistenceManagerによって永続化された各オブジェクトはDatastore内のエンティティになります。あなたのデータクラスをどのように保存し、インスタンスを再作成するのかをJDOに伝えるためアノテーションを使用します。

Note: Earlier versions of JDO use .jdo XML files instead of Java annotations. These still work with JDO 2.3. This documentation only covers using Java annotations with data classes.

注:JDOの以前のバージョンでは、アノテーションの替わりに.jdoというXMLファイルを使用していました。これはJDO2.3でも使用できます。このドキュメントではJavaアノテーションを使う場合のみをカバーします。

Class and Field Annotations

Each object saved by JDO becomes an entity in the App Engine datastore. The entity's kind is derived from the simple name of the class (inner classes use the $ path without the package name). Each persistent field of the class represents a property of the entity, with the name of the property equal to the name of the field (with case preserved).

JDOによって保存された各オブジェクトはApp Engine datastore内でエンティティとなります。エンティティの種類はクラスのシンプルネームから導出されます(インナークラスは、パッケージ名を除いた$パスを使います)。クラスの各永続化フィールドは、エンティティのプロパティとして表されます。プロパティの名前はフィールドの名前と一致します(大文字、小文字も保存されます)。

To declare a Java class as capable of being stored and retrieved from the datastore with JDO, give the class a @PersistenceCapable annotation. For example:

JavaクラスがJDOによってDatastoreに保存し、取り出すことができると宣言するには、対象のクラスに@PersistenceCapableアノテーションを付与します。次に例を示します。

import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;

@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Employee {
    // ...
}

Fields of the data class that are to be stored in the datastore must be declared as persistent fields. To declare a field as persistent, give it a @Persistent annotation:

Datastoreに格納されるデータクラスのフィールドは、永続化フィールドとして宣言しなければなりません。それには@Persistentアノテーションを付与します。

import java.util.Date;
import javax.jdo.annotations.Persistent;

// ...
    @Persistent
    private Date hireDate;

To declare a field as not persistent (it does not get stored in the datastore, and is not restored when the object is retrieved), give it a @NotPersistent annotation.

フィールドを永続化しない(Datastoreに格納せず、取り出されたときに復元しない)場合、@NotPersistentアノテーションを付与します。

Tip: JDO specifies that fields of certain types are persistent by default if neither the @Persistent nor @NotPersistent annotations are specified, and fields of all other types are not persistent by default. See the DataNucleus documentation for a complete description of this behavior. Because not all of the App Engine datastore core value types are persistent by default according to the JDO specification, we recommend explicitly annotating fields as @Persistent or @NotPersistent to make it clear.

Tip:JDOは、@Persistent と@NotPersistentアノテーションのどちらも指定されていない場合、特定の型のフィールドはデフォルトで永続化し、その他の型のフィールドは永続化しません。この振る舞いの詳細はthe DataNucleus documentationを参照してください。App Engine datastoreのコアデータ型のすべてが、JDOの仕様に従いデフォルトで保存されるわけではないため、@Persistent か@NotPersistentアノテーションを明示的に付与することをお勧めします。

The type of a field can be any of the following. These are described in detail below.

フィールドの型は次のいずれかになります。詳細は後ほど記載します。

  • one of the core types supported by the datastore
  • a Collection (such as a java.util.List<...>) or an array of values of a core datastore type
  • an instance or Collection of instances of a @PersistenceCapable class
  • an instance or Collection of instances of a Serializable class
  • an embedded class, stored as properties on the entity
  • Datastoreでサポートされているコアデータ型
  • Datastoreのコアデータ型の配列やコレクション(例えば java.util.List<...> )
  • @PersistenceCapableクラスのインスタンスやそれらのコレクション
  • Serializableクラスのインスタンスやそれらのコレクション
  • そのエンティティのプロパティとして保存された組み込みクラス

A data class must have one field dedicated to storing the primary key of the corresponding datastore entity. You can choose between 4 different kinds of key fields, each using a different value type and annotations. (See Creating Data: Keys for more information.) The simplest key field is a long integer value that is automatically populated by JDO with a value unique across all other instances of the class when the object is saved to the datastore for the first time. Long integer keys use a @PrimaryKey annotation, and a @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) annotation:

データクラスはDatastoreのエンティティと対応するプライマリキーを格納するための専用のフィールドを必ず1つもたなければなりません。異なる種類の型とアノテーションを使った、4つの異なる種類からキーのフィールドを選ぶことができます。(詳細はCreating Data: Keysを参照してください)もっとも単純なキーのフィールドはlong integerの値で、最初にDatastoreにオブジェクトを保存するときに、全てのインスタンスでユニークな値がJDOによって自動的に設定されます。Long integerキーは@PrimaryKeyアノテーションと、@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)アノテーションを使います。

Tip: Make all of your persistent fields private or protected (or package protected), and only provide public access through accessor methods. Direct access to a persistent field from another class may bypass the JDO class enhancement. Alternatively, you can make other classes @PersistenceAware. See the DataNucleus documentation for more information.

Tip:全ての永続化フィールドを private かprotected(もしくはパッケージプロテクテッド)にし、アクセサメソッドを通じてのみ公開してください。永続化フィールドに他のクラスから直接アクセスすると、JDOのクラスエンハンスメントをバイパスしてしまう場合があります。または、他のクラスを@PersistenceAwareにしてください。詳細についてはthe DataNucleus documentationを参照してください。

import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.PrimaryKey;

// ...
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Long id;

Here is an example data class:

以下はデータクラスの例です。

import java.util.Date;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Employee {
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Long id;

    @Persistent
    private String firstName;

    @Persistent
    private String lastName;

    @Persistent
    private Date hireDate;

    public Employee(String firstName, String lastName, Date hireDate) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.hireDate = hireDate;
    }

    // Accessors for the fields.  JDO doesn't use these, but your application does.

    public Long getId() {
        return id;
    }

    public String getFirstName() {
        return firstName;
    } 
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    } 

    public String getLastName() {
        return lastName;
    } 
    public void setLastName(String lastName) {
        this.lastName = lastName;
    } 

    public String getHireDate() {
        return hireDate;
    } 
    public void setHireDate(Date hireDate) {
        this.hireDate = hireDate;
    } 
}

Core Value Types

The datastore supports the following core value types:

Datastoreは次のコアデータ型をサポートします。

Type Java class Sort order Notes
short text string, < 500 bytes java.lang.String Unicode A value longer than 500 bytes throws a JDOFatalUserException.
short byte string, < 500 bytes com.google.appengine.api.datastore.ShortBlob byte order A value longer than 500 bytes throws a JDOFatalUserException.
Boolean value boolean or java.lang.Boolean false < true
integer short, java.lang.Short, int, java.lang.Integer, long, java.lang.Long Numeric Stored as long integer, then converted to the field type. Out-of-range values overflow.
floating point number float, java.lang.Float, double, java.lang.Double Numeric Stored as double-width float, then converted to the field type. Out-of-range values overflow.
date-time java.util.Date Chronological
Google account com.google.appengine.api.users.User By email address (Unicode)
long text string com.google.appengine.api.datastore.Text (not orderable) Not indexed.
long byte string com.google.appengine.api.datastore.Blob (not orderable) Not indexed.
entity key com.google.appengine.api.datastore.Key, or the referenced object (as a child) By path elements (kind, ID or name, kind, ID or name...)
a URL com.google.appengine.api.datastore.Link Unicode

Note: The datastore supports several additional core value types that are not yet implemented in the Java datastore API, but are implemented in the Python API. If a property has a value with any of these types and the entity is loaded into an object with a field for the property, JDO will behave as if the property does not exist: it will set the field to null or throw a NullPointerException if the field type is non-nullable. The unsupported types are: Category, Email, IM, PhoneNumber, PostalAddress, Rating, GeoPt.

注:PythonAPIでは実装されていますが、JavaのDatastore APIでは未実装のいくつかのコアデータ型を、Datastoreはサポートしています。それらの型の値を持つプロパティとそのエンティティを、そのプロパティ用のフィールドをもつオブジェクトにロードしようとした場合、JDOはそのプロパティが存在しないかのように振舞います。フィールドをnullに設定するか、nullを許容しない型の場合は NullPointerExceptionをスローします。未サポートの型は次のとおりです。Category、Email、IM、 PhoneNumber、PostalAddress、Rating、GeoPt。

To represent a property containing a single value of a core type, declare a field of the Java type, and use the @Persistent annotation:

コアデータ型の単一の値を格納するプロパティを表すには、Javaの型としてそのフィールドを宣言し、@Persistentアノテーションを付与します。

import java.util.Date;
import javax.jdo.annotations.Persistent;

// ...
    @Persistent
    private Date hireDate;

Serializable Objects

A field value can contain an instance of a Serializable class, storing the serialized value of the instance in a single property value of the type Blob. To tell JDO to serialize the value, the field uses the annotation @Persistent(serialized=true). Blob values are not indexed and cannot be used in query filters or sort orders.

フィールドの値にはSerializableクラスのインスタンスを格納することができます。インスタンスをシリアライズした結果をBlog型の単一のプロパティに保存します。JDOにその値をシリアライズするように伝えるには、対象のフィールドに @Persistent(serialized=true)アノテーションを付与します。Blob値はインデックスが張られず、クエリのフィルタやソート順に使うことができません。

Here is an example of a simple Serializable class that represents a file, including the file contents, a filename and a MIME type. This is not a JDO data class, so there are no persistence annotations.

次にファイル、ファイルのコンテンツ、ファイル名、MIMEタイプを表したSerializableクラスの例を挙げます。これはJDOデータクラスではありませんので、永続化アノテーションはありません。

import java.io.Serializable;

public class DownloadableFile implements Serializable {
    private byte[] content;
    private String filename;
    private String mimeType;

    // ... accessors ...
}

To store an instance of a Serializable class as a Blob value in a property, declare a field whose type is the class, and use the @Persistent(serialized = "true") annotation:

このSerializableクラスのインスタンスをBlob値としてプロパティに格納するには、そのクラスに その型のフィールドを宣言し、@Persistent(serialized = "true")アノテーションを付与します。

import javax.jdo.annotations.Persistent;
import DownloadableFile;

// ...
    @Persistent(serialized = "true")
    private DownloadableFile file;

Child Objects and Relationships

A field value that is an instance of a @PersistenceCapable class creates an owned one-to-one relationship between two objects. A field that is a collection of such references creates an owned one-to-many relationship.

@PersistenceCapableのインスタンスがフィールドの値のとき、それは2つのオブジェクト間のOwnedな1対1関連を作ります。そのような参照のコレクションであるフィールドは、Ownedな1対多関連を作ります。

Important: Owned relationships have implications for transactions, entity groups, and cascading deletes. See Transactions and Relationships for more information.

重要:Owned relationshipはトランザクション、エンティティグループ、カスケード削除に影響します。詳細はTransactionsとRelationshipsを参照してください。

Here is a simple example of an owned one-to-one relationship between an Employee object and a ContactInfo object:

次にEmployeeオブジェクトとContactInfoオブジェクト間のOwned1対1関連の例を挙げます。

ContactInfo.java

import com.google.appengine.api.datastore.Key;
// ... imports ...

@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class ContactInfo {
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Key key;

    @Persistent
    private String streetAddress;

    @Persistent
    private String city;

    @Persistent
    private String stateOrProvince;

    @Persistent
    private String zipCode;

    // ... accessors ...
}

Employee.java

import ContactInfo;
// ... imports ...

@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Employee {
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Long id;

    @Persistent
    private ContactInfo myContactInfo;

    // ... accessors ...
}

In this example, if the app creates an Employee instance, populates its myContactInfo field with a new ContactInfo instance, then saves the Employee instance with pm.makePersistent(...), the datastore creates two entities. One is of the kind "ContactInfo", representing the ContactInfo instance. The other is of the kind "Employee". The key of the ContactInfo entity has the key of the Employee entity as its entity group parent.

この例では、アプリケーションがEmployeeインスタンスを作ると、myContactInfoフィールドに新しいContactInfoインスタンスを設定します。そしてEmployeeインスタンスをpm.makePersistent(...)で保存するとき、Datastoreは2つのエンティティを作成します。1つ目は"ContactInfo"種類で、ContacInfoインスタンスを表します。もう一つは"Employee"種類です。ContacInfoエンティティのキーは、Employeeエンティティのキーをエンティティグループの親としてもちます。

Embedded Classes

Embedded classes allow you to model a field value using a class without creating a new datastore entity and forming a relationship. The fields of the object value are stored directly in the datastore entity for the containing object.

埋め込みクラスは、新しいDatasoreエンティティと関連を形成することのないクラスを使ってフィールドの値をモデリングできるようにします。そのオブジェクトの値のフィールドは、それを含むオブジェクトのDatastoreエンティティに直接保存されます。

Any @PersistenceCapable data class can be used as an embedded object in another data class. The class's @Persistent fields are embedded in the object. If you give the class to embed the @EmbeddedOnly annotation, the class can only be used as an embedded class. The embedded class does not need a primary key field because it is not stored as a separate entity.

どんな@PersistenceCapableデータクラスでも、他のデータクラスの埋め込みオブジェクトとして使うことができます。そのクラスの @Persistentフィールドは、オブジェクトに埋め込まれます。そのクラスに @EmbeddedOnlyアノテーションを付与すると、そのクラスは埋め込みクラスとしてしか使えなくなります。埋め込みクラスは、別々のエンティティとして保存されないため、プライマリキーのフィールドを必要としません。

Here is an example of an embedded class. This example makes the embedded class an inner class of the data class that uses it; this is useful, but not required to make a class embeddable.

次に埋め込みクラスの例を挙げます。この例では、データクラスの埋め込みクラスを、それお使用するデータクラスのインナークラスとしています。これは役に立ちますが、クラスを埋め込み可能とする必要はありません。

import javax.jdo.annotations.Embedded;
import javax.jdo.annotations.EmbeddedOnly;
// ... imports ...

@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class EmployeeContacts {
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    Long id;
    
    @PersistenceCapable
    @EmbeddedOnly
    public static class ContactInfo {
        @Persistent
        private String streetAddress;

        @Persistent
        private String city;

        @Persistent
        private String stateOrProvince;

        @Persistent
        private String zipCode;

        // ... accessors ...
    }

    @Persistent
    @Embedded
    private ContactInfo homeContactInfo;
}

The fields of an embedded class are stored as properties on the entity, using the name of each field and the name of the corresponding property. If you have more than one field on the object whose type is an embedded class, you must rename the fields of one so they do not conflict with another. You specify new field names using arguments to the @Embedded annotation. For example:

埋め込みクラスのフィールドは、そのエンティティのプロパティとして保存されます。各フィールドの名前を、対応するプロパティの名前として利用します。もし、そのオブジェクトに1つ以上、埋め込みクラスのタイプがある場合、ほかと競合しないようにするため、フィールドの名前を変える必要があります。新しいフィールドの名前は @Embeddedアノテーションの引数として指定することができます。次に例を挙げます。

    @Persistent
    @Embedded
    private ContactInfo homeContactInfo;

    @Persistent
    @Embedded(members = {
        @Persistent(name="streetAddress", columns=@Column(name="workStreetAddress")),
        @Persistent(name="city", columns=@Column(name="workCity")),
        @Persistent(name="stateOrProvince", columns=@Column(name="workStateOrProvince")),
        @Persistent(name="zipCode", columns=@Column(name="workZipCode")),
    })
    private ContactInfo workContactInfo;

Similarly, fields on the object must not use names that collide with fields of embedded classes, unless the embedded fields are renamed.

同様に、埋め込みフィールドをリネームしない限り、そのオブジェクトのフィールドは埋め込みクラスのフィールド名と衝突しないように命名する必要があります。

Because the embedded class's persistent properties are stored on the same entity as the other fields, you can use persistent fields of the embedded class in JDOQL query filters and sort orders. You can refer to the embedded field using the name of the outer field, a dot (.), and the name of the embedded field. This works whether or not the property names for the embedded fields have been changed using @Column annotations.

埋め込みクラスの永続化プロパティが、同じエンティティの異なるフィールドとして保存されるため、埋め込みクラスの永続化フィールドをJDOQLのクエリフィルタやソート順に利用することができます。埋め込みクラスのフィールドを外側のフィールドの名前とドット(.)で連結したもので参照することができます。これはそのプロパティ名が埋め込まれたフィールドが @Columnアノテーションでプロパティ名を変更されていてもいなくても利用することができます。

    select from EmployeeContacts where workContactInfo.zipCode == "98105"

Collections

A datastore property can have more than one value. In JDO, this is represented by a single field with a Collection type, where the collection is of one of the core value types or a Serializable class. The following Collection types are supported:

Datastoreのプロパティは1つ以上の値を持つことができます。JDOでは、コレクション型のフィールドとして表すことができます。そのコレクションはコアデータ型か、Serializableクラスを保持できます。サポートしているコレクション型を次に示します。

  • java.util.ArrayList<...>
  • java.util.HashSet<...>
  • java.util.LinkedHashSet<...>
  • java.util.LinkedList<...>
  • java.util.List<...>
  • java.util.Set<...>
  • java.util.SortedSet<...>
  • java.util.Stack<...>
  • java.util.TreeSet<...>
  • java.util.Vector<...>

If a field is declared as a List, objects returned by the datastore will have an ArrayList value. If a field is declared as a Set, the datastore returns a HashSet. If a field is declared as a SortedSet, the datastore returns a TreeSet.

フィールドがListとして宣言されている場合、DatastoreはArrayListの値を返します。フィールドがSetとして宣言されている場合はHashSet、SortedSetとして宣言されている場合はTreeSetを返します。

For example, a field whose type is List<String> is stored as zero or more string values for the property, one for each value in the List.

例えば、フィールドが Listであった場合、そのプロパティにはListの各値として0以上の文字列値が格納されます。

import java.util.List;
// ... imports ...

// ...
    @Persistent
    List<String> favoriteFoods;

A Collection of child objects (of @PersistenceCapable classes) creates multiple entities with a one-to-many relationship. See Relationships.

(@PersistenceCapableクラスの)子オブジェクトのコレクションは1対多関連をもつ複数のエンティティを作成します。Relationshipsを参照してください。

Datastore properties with more than one value have special behavior for query filters and sort orders. See Queries and Indexes: Sort Orders and Properties With Multiple Values for more information.

1以上の値を持つDatastoreのプロパティは、クエリフィルタとソート順において特殊な振る舞いをします。詳細はQueries and Indexes: Sort Orders and Properties With Multiple Valuesを参照してください。

Object Fields and Entity Properties

The App Engine datastore makes a distinction between an entity without a given property and an entity with a null value for a property. JDO does not support this distinction: every field of an object has a value, possibly null. If a field with a nullable value type (something other than a built-in type like int or boolean) is set to null, when the object is saved, the resulting entity will have the property set with a null value.

App Engine datastoreは、エンティティがプロパティを保持していないのか、プロパティの値がNullなのかを識別します。JDOはこの識別をサポートしていません。オブジェクトの各フィールドは値を持ち、nullの可能性があります。もしフィールドがnullを許容する型(intやbooleanといった組み込み型以外)の場合、オブジェクトが保存されるとき、nullをセットします。その結果のエンティティは、nullの値をもつプロパティをもちます。

If a datastore entity is loaded into an object and doesn't have a property for one of the object's fields and the field's type is a nullable single-value type, the field is set to null. When the object is saved back to the datastore, the null property becomes set in the datastore to the null value. If the field is not of a nullable value type, loading an entity without the corresponding property throws an exception. This won't happen if the entity was created from the same JDO class used to recreate the instance, but can happen if the JDO class changes, or if the entity was created using the low-level API instead of JDO.

Datastoreのエンティティがオブジェクトにロードされるとき、そのオブジェクトのフィールドに対応するプロパティが存在せず、フィールドの型がnullを許容する単一値の型である場合、そのフィールドは nullにセットされます。そのオブジェクトが再びDatastoreに保存されるとき、そのnullプロパティはDatastoreにnull値としてセットされます。もし、フィールドがnullを許容しない型の場合、対応するプロパティをもたないエンティティをロードすると例外をスローします。この事象は、同じJDOクラスを利用して再作成されたインスタンスから作られたエンティティならば起こることはありません。しかし、もしJDOクラスが変更されたり、エンティティがJDOではなく低レベルAPIを利用して作られた場合には発生することがあります。

If a field's type is a Collection of a core data type or a Serializable class and there are no values for the property on the entity, the empty collection is represented in the datastore by setting the property to a single null value. If the field's type is an array type, it is assigned an array of 0 elements. If the object is loaded and there is no value for the property, the field is assigned an empty collection of the appropriate type. Internally, the datastore knows the difference between an empty collection and a collection containing one null value.

フィールドの型がコアデータ型かSerializableクラスのコレクションで、そのエンティティのプロパティに値がない場合、データストア内では単一のnull値がそのプロパティに設定することによって空のコレクションとして表されます。フィールドの型が配列である場合、0個の要素の配列がアサインされます。内部的には、Datastoreは空のコレクションと単一のNull値の違いを知っています。

If the entity has a property that does not have a corresponding field in the object, that property is inaccessible from the object. If the object is saved back to the datastore, the extra property is deleted.

エンティティが、オブジェクトに対応するフィールドをもたないプロパティを持っていた場合、そのプロパティにはオブジェクトからアクセスできません。そのオブジェクトがDatastoreに再度保存された場合、その追加のプロパティは削除されます。

If an entity has a property whose value is of a different type than the corresponding field in the object, JDO attempts to cast the value to the field type. If the value cannot be cast to the field type, JDO throws a ClassCastException. In the case of numbers (long integers and double-width floats), the value is converted, not cast. If the numeric property value is larger than the field type, the conversion overflows without throwing an exception.

エンティティが対応するフィールドと異なる型のプロパティを持っている場合、 JDOはフィールドの型に値のキャストを試みます。キャストができない場合、JDOはClassCastExceptionをスローします。数値の場合(Long Integerと倍精度Float)、値は変換され、キャストはされません。数値プロパティの値が、対象のフィールドの型より大きい場合、例外をスローせず、変換はオーバーフローします。

0 件のコメント: