Program guide > Access data with client applications > Cache objects and their relationships (EntityManager API)


Define an entity schema

Overview

An ObjectGrid can have any number of logical entity schemas.

Entities are defined using annotated Java classes, XML, or a combination of both XML and Java classes. Defined entities are then registered with an eXtreme Scale server and bound to BackingMaps, indexes and other plug-ins.


Design an entity schema

  1. Define the entities and their relationships.

  2. Configure eXtreme Scale.

  3. Register the entities.

  4. Create entity-based applications that interact with the eXtreme Scale EntityManager APIs.


Entity schema configuration

An entity schema is a set of entities and the relationships between the entities. In an eXtreme Scale application with multiple partitions, the following restrictions and options apply to entity schemas:

Entities are registered with an ObjectGrid instance before it is initialized. Each defined entity must be uniquely named and is automatically bound to an ObjectGrid BackingMap of the same name.

The initialization method varies depending on the configuration you are using:


Local eXtreme Scale configuration

If you are using a local ObjectGrid, you can programmatically configure the entity schema. In this mode, you can use the ObjectGrid.registerEntities methods to register annotated entity classes or an entity metadata descriptor file.


Distributed eXtreme Scale configuration

If you are using a distributed eXtreme Scale configuration, provide an entity metadata descriptor file with the entity schema.


Entity requirements

Entity metadata is configured using Java class files, an entity descriptor XML file or both. At minimum, the entity descriptor XML is required to identify which eXtreme Scale BackingMaps are to be associated with entities. The persistent attributes of the entity and its relationships to other entities are described in either an annotated Java class (entity metadata class) or the entity descriptor XML file. The entity metadata class, when specified, is also used by the EntityManager API to interact with the data in the grid.

An eXtreme Scale grid can be defined without providing any entity classes. This can be beneficial when the server and client are interacting directly with the tuple data stored in the underlying maps. Such entities are defined completely in the entity descriptor XML file and are referred to as classless entities.


Classless entities

Classless entities are useful when it is not possible to include application classes in the server or client classpath. Such entities are defined in the entity metadata descriptor XML file, where the class name of the entity is specified using a classless entity identifier in the form: @<entity identifier>. The @ symbol identifies the entity as classless and is used for mapping associations between entities. See the "Classless entity metadata" figure an example of an entity metadata descriptor XML file with two classless entities defined.

If an eXtreme Scale server or client does not have access to the classes, either can still use the EntityManager API using classless entities. Common use cases include the following:

If the entity metadata is compatible between the client and server, entity metadata can be created using entity metadata classes, an XML file, or both.

For example, the "Programmatic entity class" in the following figure is compatible with the classless metadata code in the next section.

Programmatic entity class
@Entity
public class Employee {
    @Id long serialNumber;
    @Basic byte[] picture;
    @Version int ver;
    @ManyToOne(fetch=FetchType.EAGER, cascade=CascadeType.PERSIST)
    Department department;
}

@Entity
public static class Department {
    @Id int number;
    @Basic String name;
    @OneToMany(fetch=FetchType.LAZY, cascade=CascadeType.ALL, mappedBy="department")
    Collection<Employee> employees;
}


Classless fields, keys, and versions

As previously mentioned, classless entities are configured completely in the entity XML descriptor file. Class-based entities define their attributes using Java fields, properties and annotations. So classless entities need to define key and attribute structure in the entity XML descriptor with the <basic> and <id> tags.

Classless entity metadata
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://ibm.com/ws/projector/config/emd"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://ibm.com/ws/projector/config/emd ./emd.xsd">

<entity class-name="@Employee" name="Employee">
   
<attributes>
       
<id name="serialNumber" type="long"/>
       
<basic name="firstName" type="java.lang.String"/>
       
<basic name="picture" type="[B"/>
       
<version name="ver" type="int"/>
       
<many-to-one 
            name="department" 
            target-entity="@Department"
            fetch="EAGER"">
               
<cascade><cascade-persist/></cascade>
       
</many-to-one>
   
</attributes>
</entity>

<entity class-name="@Department" name="Department" >
   
<attributes>
       
<id name="number" type="int"/>
       
<basic name="name" type="java.lang.String"/>
       
<version name="ver" type="int"/>
       
<one-to-many 
            name="employees" 
            target-entity="@Employee" 
            fetch="LAZY" 
            mapped-by="department">
           
<cascade><cascade-all/></cascade>
       
</one-to-many>
   
</attributes>
</entity>

Note that each entity above has an <id> element. A classless entity must have either one or more of an <id> element defined, or a single-valued association that represents the key for the entity. The fields of the entity are represented by <basic> elements. The <id>, <version>, and <basic> elements require a name and type in classless entities. See the following supported attribute types section for details on supported types.


Entity class requirements

Class-based entities are identified by associating various metadata with a Java class. The metadata can be specified usingJava Platform, Standard Edition 5 annotations, an entity metadata descriptor file, or a combination of annotations and the descriptor file. Entity classes must meet the following criteria:

Entities all have a unique name and type. The name, if using annotations, is the simple (short) name of the class by default, but can be overridden using the name attribute of the @Entity annotation.


Persistent attributes

The persistent state of an entity is accessed by clients and the entity manager by using either fields (instance variables) or Enterprise JavaBeans-style property accessors. Each entity must define either field- or property-based access. Annotated entities are field-access if the class fields are annotated and are property-access if the getter method of the property is annotated. A mixture of field- and property-access is not allowed. If the type cannot be automatically determined, the accessType attribute on the @Entity annotation or equivalent XML can be used to identify the access type.

Persistent fields

Field-access entity instance variables are accessed directly from the entity manager and clients. Fields that are marked with the transient modifier or transient annotation are ignored. Persistent fields must not have final or static modifiers.

Persistent properties

Property-access entities must adhere to the JavaBeans signature conventions for read and write properties. Methods that do not follow JavaBeans conventions or have the Transient annotation on the getter method are ignored. For a property of type T, there must be a getter method getProperty which returns a value of type T and a void setter method setProperty(T). For boolean types, the getter method can be expressed as isProperty, returning true or false. Persistent properties cannot have the static modifier.

Supported attribute types

The following persistent field and property types are supported:

  • Java primitive types including wrappers
  • java.lang.String
  • java.math.BigInteger
  • java.math.BigDecimal
  • java.util.Date
  • java.util.Calendar
  • java.sql.Date
  • java.sql.Time
  • java.sql.Timestamp
  • byte[]
  • java.lang.Byte[]
  • char[]
  • java.lang.Character[]
  • enum

User serializable attribute types are supported but have performance, query and change-detection limitations. Persistent data that cannot be proxied, such as arrays and user serializable objects, must be reassigned to the entity if altered.

Serializable attributes are represented in the entity descriptor XML file using the class name of the object. If the object is an array, the data type is represented using the Java internal form. For example, if an attribute data type is java.lang.Byte[][], the string representation is [[Ljava.lang.Byte;

User serializable types should adhere to the following best practices:


Entity associations

Bi-directional and uni-directional entity associations, or relationships between entities can be defined as one-to-one, many-to-one, one-to-many and many-to-many. The entity manager automatically resolves the entity relationships to the appropriate key references when storing the entities.

The eXtreme Scale grid is a data cache and does not enforce referential integrity like a database. Although relationships allow cascading persist and remove operations for child entities, it does not detect or enforce broken links to objects. When removing a child object, the reference to that object must be removed from the parent.

If you define a bi-directional association between two entities, identify the owner of the relationship. In a to-many association, the many side of the relationship is always the owning side. If ownership cannot be determined automatically, then the mappedBy attribute of the annotation, or XML equivalent, must be specified. The mappedBy attribute identifies the field in the target entity that is the owner of the relationship. This attribute also helps identify the related fields when there are multiple attributes of the same type and cardinality.


Single-valued associations

One-to-one and many-to-one associations are denoted using the @OneToOne and @ManyToOne annotations or equivalent XML attributes. The target entity type is determined by the attribute type. The following example defines a uni-directional association between Person and Address.

The Customer entity has a reference to one Address entity. In this case, the association could also be many-to-one since there is no inverse relationship.

@Entity
public class Customer {
  @Id id;
  @OneToOne Address homeAddress;
}

@Entity
public class Address{
  @Id id
  @Basic String city;
}

To specify a bi-directional relationship between the Customer and Address classes, add a reference to the Customer class from the Address class and add the appropriate annotation to mark the inverse side of the relationship. Because this association is one-to-one, you have to specify an owner of the relationship using the mappedBy attribute on the @OneToOne annotation.

@Entity
public class Address{
  @Id id
  @Basic String city;
  @OneToOne(mappedBy="homeAddress") Customer customer;
}


Collection-valued associations One-to-many and many-to-many associations are denoted using the @OneToMany and @ManyToMany annotations or equivalent XML attributes. All many relationships are represented using the types: java.util.Collection, java.util.List or java.util.Set. The target entity type is determined by the generic type of the Collection, List or Set or explicitly using the targetEntity attribute on the @OneToMany or @ManyToMany annotation (or XML equivalent).

In the previous example, it is not practical to have one address object per customer because many customers might share an address or might have multiple addresses. This situation is better solved using a many association:

@Entity
public class Customer {
  @Id id;
  @ManyToOne Address homeAddress;
  @ManyToOne Address workAddress;
}

@Entity
public class Address{
  @Id id
  @Basic String city;
  @OneToMany(mappedBy="homeAddress") Collection<Customer> homeCustomers;


  @OneToMany(mappedBy="workAddress", targetEntity=Customer.class) 
        Collection workCustomers;
}

In this example, two different relationships exist between the same entities: a Home and Work address relationship. A non-generic Collection is used for the workCustomers attribute to demonstrate how to use the targetEntity attribute when generics are not available.


Classless associations

Classless entity associations are defined in the entity metadata descriptor XML file similar to how class-based associations are defined. The only difference is that instead of the target entity pointing to an actual class, it points to the classless entity identifier used for the class name of the entity.

An example follows:

<many-to-one name="department" target-entity="@Department" fetch="EAGER">
     
<cascade><cascade-all/></cascade>
</many-to-one>
<one-to-many name="employees" target-entity="@Employee" fetch="LAZY">
     
<cascade><cascade-all/></cascade>
</one-to-many>


Primary keys

All entities must have a primary key, which can be a simple (single attribute) or composite (multiple attribute) key. The key attributes are denoted using the Id annotation or defined in the entity XML descriptor file. Key attributes have the following requirements:

Composite primary keys can optionally define a primary key class. An entity is associated with a primary key class using the @IdClass annotation or the entity XML descriptor file. An @IdClass annotation is useful in conjunction with the EntityManager.find method.

Primary key classes have the following requirements:

An example follows:

@Entity
@IdClass(CustomerKey.class)
public class Customer {
    @Id @ManyToOne Zone zone;
    @Id int custId;
    String name;
    ...
}

@Entity
public class Zone{
    @Id String zoneCode;
    String name;
}

public class CustomerKey {
    Zone zone;
    int custId;

    public int hashCode() {...}
    public boolean equals(Object o) {...}
}


Classless primary keys

Classless entities are required to either have at least one <id> element or an association in the XML file with the attribute id=true. An example of both would look like the following:

<id name="serialNumber" type="int"/>
<many-to-one name="department" target-entity="@Department" id="true">
<cascade><cascade-all/></cascade>
</many-to-one>

Remember: The <id-class> XML tag is not supported for classless entities.


Entity proxies and field interception

Entity classes and mutable supported attribute types are extended by proxy classes for property-access entities and bytecode-enhanced for Java Development Kit (JDK) 5 field-access entities. All access to the entity, even by internal business methods and the equals methods, must use the appropriate field or property access methods.

Proxies and field interceptors are used to allow the entity manager to track the state of the entity, determine if the entity has changed, and improve performance. Field interceptors are only available on Java SE 5 platforms when the entity instrumentation agent is configured.

Attention: When using property-access entities, the equals method should use the instanceof operator for comparing the current instance to the input object. All introspection of the target object should be through the properties of the object, not the fields themselves, because the object instance will be the proxy.


Parent topic:

Cache objects and their relationships (EntityManager API)


Related concepts

EntityManager in a distributed environment

Interacting with EntityManager

EntityManager fetch plan support

EntityManager interface performance impact

Entity query queues


Related tasks

Entity manager tutorial: Overview

Related reference

EntityTransaction interface