users@jpa-spec.java.net

[jpa-spec users] [jsr338-experts] Entity Graphs

From: Linda DeMichiel <linda.demichiel_at_oracle.com>
Date: Sun, 09 Dec 2012 15:04:55 -0800

I've spec'd out a more detailed version of the proposal. Please review and comment.

thanks,

-Linda

-------------------------------

Section: Entity Graphs

An entity graph is a template that is defined in the form of metadata
or an object created by the dynamic EntityGraph API and that captures
the path and boundaries for an operation or query.

Entity graphs are used in the specification of "fetch plans" for
query or find operations and as specifications for the boundaries
of merge or copy operations.


Subsection: Use of Entity Graphs in find and query operations

An entity graph can be used with the find operation or as a query
hint to override or augment FetchType semantics.

The standard properties javax.persistence.fetchgraph and
javax.persistence.loadgraph are used to specify such graphs to queries
and find operations.

The default fetch graph for an entity or embeddable is defined to
consist of the transitive closure of all of its attributes that are
specified as FetchType.EAGER (or defaulted as such).

The persistence provider is permitted to fetch additional entity state
beyond that specified by a fetch graph or load graph. It is required,
however, that the persistence provider fetch all state specified by the
fetch or load graph.

Subsectionsection: Fetch graph semantics

When the javax.persistence.fetchgraph property is used to specify an
entity graph, attributes that are specified by attribute nodes of the
entity graph are treated as FetchType.EAGER and attributes that are
not specified are treated as FetchType.LAZY. The primary key and
version attributes of an entity are always retrieved, even if not
specified by the fetch graph.

The following rules apply, depending on attribute type. The rules of
this section are applied recursively.

A primary key or version attribute never needs to be specified in an
attribute node of a fetch graph. (This applies to composite primary
keys as well, including embedded id primary keys.) When an entity is
fetched, its primary key and version attributes are always fetched.
It is not incorrect, however, to specify primary key attributes or
version attributes.

Attributes other than primary key and version attributes are assumed
not to be fetched unless the attribute is specified. The following
rules apply to the specification of attributes:

If the attribute is an embedded attribute, and the attribute is
specified in an attribute node, but a subgraph is not specified for
the attribute, the default fetch graph for the embeddable is fetched.
If a subgraph is specified for the attribute, the attributes of the
embeddable are fetched according to their specification in the
corresponding subgraph.

If the attribute is an element collection of basic type, and the
attribute is specified in an attribute node, the element collection
together with its basic elements is fetched.

If the attribute is an element collection of embeddables, and the
attribute is specified in an attribute node, but a subgraph is not
specified for the attribute, the element collection together with the
default fetch graph of its embeddable elements is fetched. If a
subgraph is specified for the attribute, the attributes of the
embeddable elements will be fetched according to the corresponding
subgraph specification.

If the attribute is a one-to-one or many-to-one relationship, and the
attribute is specified in an attribute node, but a subgraph is not
specified for the attribute, the default fetch graph of the target
entity is fetched. If a subgraph is specified for the attribute, the
attributes of the target entity will be fetched according to the
corresponding subgraph specification.

If the attribute is a one-to-many or many-to-many relationship, and
the attribute is specified in an attribute node, but a subgraph is not
specified, the collection will be fetched and the default fetch graphs
of the referenced entities will be fetched. If a subgraph is
specified for the attribute, the entities in the collection will be
fetched according to the corresponding subgraph specification.

If the key of a map which has been specified in an attribute node is a
basic type, it will always be fetched. If the key of a map which has
been specified in an attribute node is an embedded type the default
fetch graph will be fetched for the embeddable. Otherwise, if the key
of the map is an entity, and a map key subgraph is not specified for
the attribute node, the map key will be fetched according to its
default fetch graph. If a key subgraph is specified for the map key
attribute, the map key attribute will be fetched according to the map
key subgraph specification.

Example:

@NamedEntityGraph
@Entity
public class Phonenumber{
     @Id
     protected String number;

     protected PhoneTypeEnum type;
    ...
}

In this example, only the number attribute would be eagerly fetched.



Example:

@NamedEntityGraph(
   attributeNodes={
     @NamedAttributeNode("projects")
   }
)
@Entity
public class Employee{

   @Id
   @GeneratedValue
   protected long id;

   @Basic
   protected String name;

   @Basic
   protected String employeeNumber;

   @OneToMany()
   protected List<Dependants> dependants;

   @OneToMany()
   protected List<Project> projects;

   @OneToMany()
   protected List<PhoneNumber> phoneNumbers;
   ...
}

@Entity
@Inheritance
public class Project{
     @Id
     @GeneratedValue
     protected long id;

     String name;

     @OneToOne(fetch=FetchType.EAGER)
     protected Requirements doc;
    ...
}

@Entity
public class LargeProject extends Project{

     @OneToOne(fetch=FetchType.LAZY)
     protected Employee approver;
    ...
}



@Entity
public class Requirements{
     @Id
     protected long id;

     @Lob
     protected String description;

     @OneToOne(fetch=FetchType.LAZY)
     protected Approval approval
    ...
}


In the above example, the Employee entity's primary key will be
fetched as well as the related project instances, whose default fetch
graph (id, name, and doc attributes) will be fetched. The related
Requirements object will be fetched according to its default fetch
graph.

If the approver attribute of LargeProject were FetchType.EAGER, and
if any of the projects were instances of LargeProject, their approver
attributes would also be fetched. Since the type of the approver
attribute is Employee, the approver's default fetch graph (id, name,
and employeeNumber attributes) would also be fetched.




Subsubsection: Load graph semantics:

When the javax.persistence.loadgraph property is used to specify an
entity graph, attributes that are specified by attribute nodes of the
entity graph are treated as FetchType.EAGER and attributes that are
not specified are treated according to their specified or default
FetchType. The primary key and version attributes of an entity are
always retrieved.

The following rules apply. The rules of this section are applied recursively.

A primary key or version attribute never needs to be specified in an
attribute node of a load graph. (This applies to composite primary
keys as well, including embedded id primary keys.) When an entity is
fetched, its primary key and version attributes are always fetched.
It is not incorrect, however, to specify primary key attributes or
version attributes.

If the attribute is an embedded attribute, and the attribute is
specified in an attribute node, the default fetch graph for the
embeddable is fetched. If a subgraph is specified for the attribute,
attributes that are specified by the subgraph are also fetched.

If the attribute is an element collection of basic type, and the
attribute is specified in an attribute node, the element collection
together with its basic elements is fetched.

If the attribute is an element collection of embeddables, and the
attribute is specified in an attribute node, the element collection
together with the default fetch graph of its embeddable elements is
fetched. If a subgraph is specified for the attribute, attributes
that are specified by the subgraph are also fetched.

If the attribute is a one-to-one or many-to-one relationship, and the
attribute is specified in an attribute node, the default fetch graph
of the target entity is fetched. If a subgraph is specified for the
attribute, attributes that are specified by the subgraph are also
fetched.

If the attribute is a one-to-many or many-to-many relationship, and
the attribute is specified in an attribute node, the collection will
be fetched and the default fetch graphs of the referenced entities
will be fetched. If a subgraph is specified for the attribute,
attributes that are specified by the subgraph are also fetched.

If a collection-valued attribute is a map, and the map-valued
attribute is specified in an attribute node, keys that are basic or
embeddable types will be fetched when the map is fetched; entity map
key attributes will be fetched according to the default fetch graph
and, if a key subgraph is specified, additional entity attributes are
fetched as specified in the subgraph.

Example:

@NamedEntityGraph
@Entity
public class Phonenumber{
     @Id
     protected String number;

     protected PhoneTypeEnum type;
    ...
}

In the above example, the number and type attributes are loaded.


Example:

@NamedEntityGraph(
   attributeNodes={
     @NamedAttributeNode("projects")
   }
)
@Entity
public class Employee{

   @Id
   @GeneratedValue
   protected long id;

   @Basic
   protected String name;

   @Basic
   protected String employeeNumber;

   @OneToMany()
   protected List<Dependants> dependants;

   @OneToMany()
   protected List<Project> projects;

   @OneToMany()
   protected List<PhoneNumber> phoneNumbers;
   ...
}

@Entity
@Inheritance
public class Project{
     @Id
     @GeneratedValue
     protected long id;

     String name;

     @OneToOne(fetch=FetchType.EAGER)
     protected Requirements doc;
    ...
}

@Entity
public class LargeProject extends Project{

     @OneToOne(fetch=FetchType.LAZY)
     protected Employee approver;
    ...
}



@Entity
public class Requirements{
     @Id
     protected long id;

     @Lob
     protected String description;

     @OneToOne(fetch=FetchType.LAZY)
     protected Approval approval
    ...
}

In the above example, the default fetch graph (id, name, and
employeeNumber) of Employee is loaded. The default fetch graphs of
the related Project instances (id, name, and doc attributes) and their
Requirements instances (id and description attributes) are also
loaded.



Subsection: Merge graph semantics

An entity graph may be used as a "merge graph" and passed as an
argument to the merge method.

The following semantics apply to entity graphs that are used as merge
graphs.

A merge graph attribute node specified within an entity graph or
subgraph specifies how an attribute is to be merged. Primary key and
version attributes do not need to be specified in the merge graph. If
other attributes are not specified, they are not merged. Note that
cascade=MERGE specifications are ignored.

The persistence provider must observe the scope and boundaries of a
merge graph specification exactly.

The following additional rules apply for attributes that are
specified in attribute nodes. These rules are applied recursively.

If the attribute is an embedded attribute and a subgraph is not
specified for the attribute, the embedded attribute is merged but the
attributes of the embeddable are not merged. If a subgraph is
specified for the attribute, the attributes of the embeddable are
merged according to their specification in the corresponding subgraph.

If the attribute is an element collection of basic type, the element
collection is merged. The values in the element collection are
replaced.

If the attribute is an element collection of embeddables and a
subgraph is not specified for the attribute, the element collection is
merged. The values in the element collection are replaced and all
attributes of the embeddables are included. If a subgraph is
specified for the attribute, the values in the element collection are
replaced and all attributes of the embeddables are included, and the
attributes specified in the subgraph are processed according to the
subgraph specification.

If the attribute is a one-to-one or many-to-one relationship and a
subgraph is not specified for the attribute, the attribute is merged,
but the attributes of the target entity are not merged. If a subgraph
is specified for the attribute, the attributes of the target entity
will be merged according to the corresponding subgraph specification.

If the attribute is a one-to-many or many-to-many relationship and a
subgraph is not specified for the attribute, the attribute is merged,
but the attributes of the target entity are not merged. If a subgraph
is specified for the attribute, the entities in the collection will be
merged according to the corresponding subgraph specification.

   In both of the two relationship cases above, note that if a new
   entity (entity in the "new" state) was added to the relationship and
   only a subset of its attributes is specified in the subgraph, only
   those specified attributes are copied.

If the attribute is a map, the map key will be merged. If the map key
is an embeddable, all attributes of the embeddable are included. If
the map key is an entity, the attribute is merged, but the attributes
of the target entity are not merged. If a subgraph is specified for
the attribute, the target entity is merged according to the corresponding
subgraph specification.


Example:

@NamedEntityGraph(
     attributeNodes={
         @NamedAttributeNode("name"),
         @NamedAttributeNode(
             value="projects",
             subGraph="projects"
         ),
         @NamedAttributeNode("phoneNumbers"),
     },
     subGraphs={
         @NamedSubGraph(
             name="projects",
             attributeNodes={
                 @NamedAttributeNode("doc")
             }
         )
     }
)
@Entity
public class Employee{

   @Id
   @GeneratedValue
   protected long id;

   @Basic
   protected String name;

   @Basic
   protected String employeeNumber;

   @OneToMany()
   protected List<Dependants> dependants;

   @OneToMany()
   protected List<Project> projects;

   @OneToMany()
   protected List<PhoneNumber> phoneNumbers;
   ...
}

@Entity
public class Phonenumber{
     @Id
     protected String number;

     protected PhoneTypeEnum type;
    ...
}


@Entity
@Inheritance
public class Project{
     @Id
     @GeneratedValue
     protected long id;

     String name;

     @OneToOne(fetch=FetchType.EAGER)
     protected Requirements doc;
    ...
}

In the above example, the name attribute and the projects and phoneNumbers
collections will be merged. Within projects, only the doc attribute will
be merged. No attributes of phoneNumbers will be merged.



Subsection: Copy graph semantics

An entity graph may be used as a "copy graph" and passed as an
argument to the copy method.

The copy method is intended for use in disconnecting a graph of
entities from a larger graph. When using an entity graph in
combination with the copy operation, a copy of the entity is created
and the attributes of the copied entity are populated based on copies
of the attributes listed in the entity graph.

The following semantics apply to entity graphs that are used as copy
graphs.

The persistence provider must observe the scope and boundaries of a
copy graph specification exactly.

OPEN ISSUE: If a copy graph specifies an attribute that has not
yet been loaded, should it be loaded?

The following rules apply to the specification of attributes. The
rules of this section are applied recursively.

Primary key and version attributes are always copied.
Attributes are otherwise not copied unless they are specified.

If the attribute is an embedded attribute and an attribute node is
specified for the attribute but a subgraph is not specified for the
attribute, a new instance of the embeddable is inserted into the
resulting copy of the entity graph, but no state is copied. If a
subgraph is specified for the attribute, the attributes of the
embeddable are copied according to their specification in the
corresponding subgraph.

If the attribute is an element collection of basic type, the element
collection and its contents are copied.

If the attribute is an element collection of embeddables and an
attribute node is specified for the attribute but a subgraph is not
specified, a new collection is created and new embeddables instances
are inserted into it, but no state is copied. If a subgraph is
specified for the attribute, the embeddables are copied according to
their specification in the subgraph.

If the attribute is a one-to-one or many-to-one relationship and an
attribute node is specified for the attribute, but a subgraph is not
specified, a copy of the entity is created and inserted. Only the
primary key and version attributes of the entity are copied. If a
subgraph is specified for the attribute, a copy of the entity is
created and inserted and the attributes of the target entity are
copied according to the corresponding subgraph specification along
with the primary key and version attributes.

If the attribute is a one-to-many or many-to-many relationship and an
attribute node is specified for the attribute, but a subgraph is not
specified, a new collection is created and inserted, and copies of the
referenced entities are created and inserted into the collection.
Only the primary key and version attributes of these entities are
copied. If a subgraph is specified for the attribute, the entities in
the collection will be copied according to the corresponding subgraph
specification along with the primary key and version attributes.

If the attribute is a map and an attribute node has been specified for
the attribute:
    if the map key attribute is a basic type, it is copied;
    if the map key attribute is an embedded attribute, a new instance of the
        embeddable is inserted but no state is copied;
    if the map key attribute is an entity, a copy of the entity is created,
        and only the primary key and version attributes of the entity are copied.
    If a subgraph is specified for the embeddable or entity, the attributes
        of the target are copied according to the corresponding map key
        subgraph specification.


Example:

@NamedEntityGraph(
     attributeNodes={
         @NamedAttributeNode("name"),
         @NamedAttributeNode(
             value="projects",
             subGraph="projects"
         ),
         @NamedAttributeNode("phoneNumbers"),
     },
     subGraphs={
         @NamedSubGraph(
             name="projects",
             attributeNodes={
                 @NamedAttributeNode("doc")
             }
         )
     }
)
@Entity
public class Employee{

   @Id
   @GeneratedValue
   protected long id;

   @Basic
   protected String name;

   @Basic
   protected String employeeNumber;

   @OneToMany()
   protected List<Dependants> dependants;

   @OneToMany()
   protected List<Project> projects;

   @OneToMany()
   protected List<PhoneNumber> phoneNumbers;
   ...
}

@Entity
public class Phonenumber{
     @Id
     protected String number;

     protected PhoneTypeEnum type;
    ...
}


@Entity
@Inheritance
public class Project{
     @Id
     @GeneratedValue
     protected long id;

     String name;

     @OneToOne(fetch=FetchType.EAGER)
     protected Requirements doc;
    ...
}

In the above example, a new Employee instance will be created and the
values of the id and name attributes copied. The projects and
phoneNumbers collections are recreated and populated in the copy. For
the entities within the new projects collection, the id attributes are
copied and new Requirements objects created. Only the id attribute of
the Requirement entity is copied. For the entities within the new
phoneNumbers collection, only the number attribute is copied.