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
- Define the entities and their relationships.
- Configure eXtreme Scale.
- Register the entities.
- 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:
- Each entity schema must have a single root defined. This is known as the schema root.
- All the entities for a given schema must be in the same map set, which means that all the entities that are reachable from a schema root with key or non-key relationships must be defined in the same map set as the schema root.
- Each entity can belong to only one entity schema.
- Each eXtreme Scale application can have multiple 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 configurationIf 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 configurationIf 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:
- The eXtreme Scale container is hosted in a server that does not allow application classes in the classpath. In this case, the clients can still access the grid using the EntityManager API from a client, where the classes are allowed.
- The eXtreme Scale client does not require access to the entity classes because the client is either using a non-Java client, such as the eXtreme Scale REST data service or the client is accessing the tuple data in the grid using the ObjectMap API.
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:
- The @Entity annotation is specified in the entity XML descriptor file.
- The class has a public or protected no-argument constructor.
- It must be a top-level class. Interfaces and enumerated types are not valid entity classes.
- Cannot use the final keyword.
- Cannot use inheritance.
- Must have a unique name and type for each ObjectGrid instance.
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:
- Implement high performance serialization methods. Implement the java.lang.Cloneable interface and public clone method.
- Implement the java.io.Externalizable interface.
- Implement equals and hashCode
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 associationsOne-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 associationsClassless 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:
- The value of a primary key cannot change.
- A primary key attribute should be one of the following types: Java primitive type and wrappers, java.lang.String, java.util.Date or java.sql.Date.
- A primary key can contain any number of single-valued associations. The target entity of the primary key association must not have an inverse association directly or indirectly to the source entity.
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:
- It should be public with a no-argument constructor.
- The access type of the primary key class is determined by the entity that declares the primary key class.
- If property-access, the properties of the primary key class must be public or protected.
- The primary key fields or properties must match the key attribute names and types defined in the referencing entity.
- Primary key classes must implement the equals and hashCode methods.
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 keysClassless 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.
- emd.xsd file
Use the entity metadata XML schema definition to create a descriptor XML file and define an entity schema for WebSphere eXtreme Scale.
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
Related tasks
Entity manager tutorial: Overview
Related reference