users@jpa-spec.java.net

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

From: Gordon Yorke <gordon.yorke_at_oracle.com>
Date: Wed, 30 Jan 2013 09:29:13 -0500

Yes, they should although it may be easier to support more inspection in
the future if AttributeNode.getSubgraps()
AttributeNode.getKeySubgraphs() were to exist or planned to exist. The
alternate pattern that will be needed of isKeySubgraph() is not a great
pattern. I think we should add this simple methods to this release if
possible.
--Gordon


On 29/01/2013 5:42 PM, Steve Ebersole wrote:
> Also related... Do EntityGraph.getAttributeNodes /
> Subgraph.getAttributeNodes return Subgraphs in the AttributeNode list?
>
> On Tue 29 Jan 2013 04:14:13 PM CST, Steve Ebersole wrote:
>> What is the proposed behavior of EntityGraph or Subgraph when
>> addAttributeNodes is called with non-basic attribute types (a
>> ManyToOne for example)? Is that considered an exception condition?
>> And if so, what exception (IllegalArgumentException)? Or do providers
>> simply interpret it as a call to addSubgraph?
>>
>> Also, a minor edit to report in the spec, at least as of the Public
>> Review Draft. In the definition of the NamedEntityGraph annotation,
>> the type of subclassSubgraphs is defined as NamedSubGraph[] rather
>> than NamedSubgraph[]
>>
>>
>> On Sun 09 Dec 2012 05:04:55 PM CST, Linda DeMichiel wrote:
>>> 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.
>>>
>>>
>>>