Jump to: navigation, search

Difference between revisions of "EclipseLink/UserGuide/JPA/Advanced JPA Development/Extensible Entities"

(Examples)
(Configuring the EntityManagerFactory and the Metadata Repository)
Line 332: Line 332:
 
{{EclipseLink_JPA }}
 
{{EclipseLink_JPA }}
  
*'''refreshMetadata() is important.  We should indicate that if you change the metadata and you want an EntityManager based on the new metadata, you call refreshMetadata on the EntityManagerFactory and then the next EntityManager you get will be based on the new metadata.  Additionally, refreshMetadata takes a Map of properties and that map of properties can be used to override the properties previously defined for the metadata-source.
+
*'''refreshMetadata() is important.  We should indicate that if you change the metadata and you want an EntityManager based on the new metadata, you call refreshMetadata on the EntityManagerFactory and then the next EntityManager you get will be based on the new metadata.  Additionally, refreshMetadata takes a Map of properties and that map of properties can be used to override the properties previously defined for the metadata-source.'''--[[User:Tom.ware.oracle.com|Tom.ware.oracle.com]] 17:36, 28 June 2011 (UTC)

Revision as of 13:36, 28 June 2011

EclipseLink JPA

link="http://wiki.eclipse.org/EclipseLink"
EclipseLink
Website
Download
Community
Mailing ListForumsIRC
Bugzilla
Open
Help Wanted
Bug Day
Contribute
Browse Source

Extensible Entities

This feature is new in EclipseLink 2.3.

This topic is currently under review.

Use the @VirtualAccessMethods annotation to specify that an entity is extensible. By using virtual properties in an extensible entity, you can specify mappings external to the entity. This allows you to modify the mappings without modifying the entity source file and without redeploying the entity's persistence unit.

Extensible entities are useful in a multi-tenant (or Software-as-a-Service) environment where a shared, generic application can be used by multiple clients (tenants). Tenants have private access to their own data, as well as to data shared with other tenants. See also Single-Table Multi-Tenancy.

Using extensible entities, you can:

  • Build an application where some mappings are common to all users and some mappings are user-specific.
  • Add mappings to an application after it is made available to a customer (even post-deployment).
  • Use the same EntityManagerFactory to work with data after mappings have changed.
  • Provide an additional source of metadata to be used by an application.

To configure extensible entities, you must do the following:

  1. add a get(String) method and a set(String, Object) method and the datastructures necessary to support them to your Entity.--Tom.ware.oracle.com 15:47, 28 June 2011 (UTC)
  2. Configure the entity with @VirtualAccessMethods to specify that the entity is extensible and to define virtual properties. See Configuring the Entity.
  3. Include flexible columns in the database table to store the additional data. See Designing the Schema.
  4. Specify extended mappings in the eclipselink-orm.xml file. See Providing Additional Mappings
  5. Configure persistence.xml. See Configuring persistence.xml.

Configuring the Entity

Use the @VirtualAccessMethods annotation to specify that an entity allows flexible mappings.

@VirtualAccessMethods Attributes
Attribute Description Default Required?
get The name of the getter method to use for the virtual property This method must take a single java.lang.String parameter and return a java.lang.Object. get No
set The name of the setter method to use for the virtual property This method must take a java.lang.String parameter and return a java.lang.Object parameter. set No
  • We should mention the required signatures of these methods here. (get(String) and set(String, Object)) Our weaving will not work with other signatures--Tom.ware.oracle.com 15:52, 28 June 2011 (UTC)
  • What does "Required: No" mean?--Tom.ware.oracle.com 15:52, 28 June 2011 (UTC)



An extensible entity class must have a get() method that returns a value by property name and a set() method that stores a value by property name. The default names for these methods are get() and set(), and they can be overridden with the @VirtualAccessMethods annotation.

EclipseLink weaves these methods if weaving is enabled, which provides support for lazy loading, change tracking, fetch groups, and internal optimizations.

Elug note icon.png

Note: Weaving is not supported when using virtual access methods with OneToOne mappings. If attempted, an exception will be thrown.

An extended entity stores extended attributes in a Map, and values from the Map are mapped to the database using an eclipselink-orm.xml mapping file.

Use the @Transient annotation to ...

//REVIEWERS: What is the right thing to say about Transient? The MOXy extensibility sample doc says "Use @Transient annotation to prevent the entity from being mapped as an inheritance relationship," but I don't think that is right for JPA> My understanding of transient in JPA is that it means a property or field isn't persisted. So what should be said here about transient? (including, is @Transient required when specifying virtual properties?) These issues also come up in the explanations for the examples, below, where the design doc says something like " Extensions are mapped in a portable way using Transient ".//

  • @Transient is really just something to remind users to keep in mind. If they are using FIELD based access any underlying data structure they use to store the virtual mappings should be @Transient so that JPA will not try to use that data structure to for another mapping. With PROPERTY access, there is no need for @Transient --Tom.ware.oracle.com 15:56, 28 June 2011 (UTC)

Example

Add a comment here that indicates this is an Entity that uses PROPERTY access, or maybe just the "id" field I have added below in the source --Tom.ware.oracle.com 17:18, 28 June 2011 (UTC)

@Entity
  @VirtualAccessMethods
  public class Customer{
 
    @Id
    private int id;
...
 
    @Transient
    private Map<String, Object> extensions;
 
    public <T> T get(String name) {
        return (T) extentions.get(name);
    }
 
    public Object set(String name, Object value) {
        return extensions.put(name, value);
    }

Designing the Schema

Provide database tables with extra columns for storing flexible mapping data. For example, the following Customer table includes two predefined columns, ID and NAME, and three flexible columns, FLEX_COL1, FLEX_COL2, FLEX_COL3:

  • CUSTOMER
    • INTEGER ID
    • VARCHAR NAME
    • VARCHAR FLEX_COL1
    • VARCHAR FLEX_COL2
    • VARCHAR FLEX_CO31

You can then specify which of those flex columns should be used to persist an extended attribute, as described below, in Providing Additional Mappings.

Providing Additional Mappings

To provide additional mappings, add the mappings to the eclipselink-orm.xml file, for example:

<basic name="idNumber" attribute-type="String">
  <column name="FLEX_COL1"/>
  <access-methods get-method="get" set-method="set"/>
</basic>

//REVIEWERS: Are there any limitations on the types of mappings that support flexible mappings? Also, do you think anything more should be said about what you have to do in eclipselink-orm.xml?//

  • I think that part of this will be addressed by anything we do to document using <access-methods> to specify Virtual mappings--Tom.ware.oracle.com 16:04, 28 June 2011 (UTC)
  • The XML file simply gets treated as another XML file in the list of XML files. As long as you obey all the rules related to what can be overridden, you can use any kind of mapping. The challenge in using non-virtual mappings is how to have the data structures that support them make sense when the document is not there. e.g. if you're going to have an extension that uses an instance variable, for the instances of the application that don't use that extension file, how is that instance variable treated - JPA will likely try to use it for a mapping using its defaulting-rules --Tom.ware.oracle.com 16:04, 28 June 2011 (UTC)

Configuring persistence.xml

Configure persistence unit properties in persistence.xml to indicate that the application should retrieve the flexible mappings from the eclipselink-orm.xml file,. For example:

//REVIEWERS Did I get that intro right? Would different wording be better here? The design doc said “Use persistence unit properties to get your application to use the file."//

  • Both persistence unit propeties and persistence.xml are legitimate use cases. We should describe both. persistence.xml allows either a default, or a single-user file that can be changed. persistence unit properties allow specification of the file at runtime and provides a more dynamic experience.--Tom.ware.oracle.com 16:06, 28 June 2011 (UTC)
<property name="eclipselink.metadata-source" value="XML"/>
<property name="eclipselink.metadata-source.xml.url" value="foo://bar"/>

//REVIEWERS What more can be said about these? See my related questions below, under Configuring the EntityManagerFactory and the Metadata Repository.//

  • Maybe the two sections should go together. We could mention that by default we support using a file at a URL, but it is possible to also override how the repository works and then go into details.--Tom.ware.oracle.com 17:20, 28 June 2011 (UTC)

Examples

The following examples illustrate variations on configuring extensible entities.

Example 1

Example 1 illustrates the following:

  • Field access is used for non-extension fields.
  • Virtual access is used for extension fields, using defaults (get(String) and set(String, Object)) .
  • The get(String) and set(String, Object) methods will be woven, even if no mappings use them, because of the presence of @Extensible.

// REVIEWERS: All the examples make this point about @Extensible, but I don't see @Extensible used elsewhere in this spec, in the Javadoc, or in the sample; and I don't see <extensible> in eclipselink-orm.xsd. Does it exist? If it does not exist, should this bullet be rewritten to say something new about weaving, or should I delete it?//

  • Replace "Extensible" with "VirtualAccessMethods". I'll fix the other doc.--Tom.ware.oracle.com 17:22, 28 June 2011 (UTC)
  • Extensions are mapped in a portable way by specifying @Transient.

// REVIEWERS: See my question earlier about @Transient, under "Configuring the Entity." In short, what should be said here about using @Transient?//

  • Let me know if that is not covered in the original comments--Tom.ware.oracle.com 17:22, 28 June 2011 (UTC)


Example 1

@Entity
  @VirtualAccessMethods
  public class Address {
 
    @Id
    private int id;
 
    @Transient
    private Map<String, Object> extensions;
 
    public int getId(){
        return id;
    }
 
    public <T> T get(String name) {
        return (T) extentions.get(name);
    }
 
    public Object set(String name, Object value) {
        return extensions.put(name, value);
    }
 
...

Example 2

Example 2 illustrates the following:

  • Field access is used for non-extension fields.
  • The @VirtualAccessMethods annotation overrides methods to be used for getting and setting.
  • The getExtension(String) and setExtension(String, Object) methods will be woven, even if no mappings use them, because of the presence of @Extensible

// REVIEWERS: See my question about @Extensible in example 1.//

  • Extensions are mapped in a portable way by specifying @Transient.

// REVIEWERS: See my question about @Transient in example 1.//

  • The XML for extended mapping indicates which get() and set() method to use.


Example 2

@Entity
  @VirtualAccessMethods(get="getExtension", set="setExtension")
  public class Address {
 
    @Id
    private int id;
 
    @Transient
    private Map<String, Object> extensions;
 
    public int getId(){
        return id;
    }
 
    public <T> T getExtension(String name) {
        return (T) extensions.get(name);
    }
 
    public Object setExtension(String name, Object value) {
        return extensions.put(name, value);
    }
 
...
<basic name="name" attribute-type="String">
      <column name="FLEX_1"/>
      <access-methods get-method="getExtension" set-method="setExtension"/>
    </basic>

Example 3

Example 3 illustrates the following:

  • Property access is used for non extension fields.
  • Virtual access is used for extension fields, using defaults (get(String) and set(String, Object))
  • The extensions are mapped in a portable way; no @Transient is required because property access is used.

//REVIEWERS: Why? See also my comments on @Transient in example 1//

  • The get(String) and set(String, Object) methods will be woven, even if no mappings use them, because of the presence of @Extensible.

//REVIEWERS: See also comments about @Extensible in example 1//

@Entity
  @VirtualAccessMethods
  public class Address {
 
    private int id;
 
    private Map<String, Object> extensions;
 
    @Id
    public int getId(){
        return id;
    }
 
    public <T> T get(String name) {
        return (T) extensions.get(name);
    }
 
    public Object set(String name, Object value) {
        return extensions.put(name, value);
    }
 
...

Configuring the EntityManagerFactory and the Metadata Repository

//REVIEWERS: I'm not sure about this section. Are these mostly implementation details whose user-facing information is already discussed above? Or should we retain this section to delve deeper into these subjects? If so, please advise what to say here.//

  • I think think this section can be fairly brief. A quick intro to what the repository does and then an indication that it is possible to provide an overriding class and a pointer to the XML that provides the classname--Tom.ware.oracle.com 17:30, 28 June 2011 (UTC)

Extensions are added at bootstrap time through access to a metadata repository. The metadata repository is accessed through a class that provides methods to retrieve the metadata it holds.

Specify the class to use and any configuration information for the metadata repository through persistence unit properties. The entity manager factory checks the metadata repository while bootstrapping for additional mapping information. If additional mapping information is found, the entity manager factory integrates the into the metadata it uses to bootstrap.

Two types of metadata repository are supported: XML and database.

  • There is no "database" at the moment. I'll fix the other doc--Tom.ware.oracle.com 17:30, 28 June 2011 (UTC)

You can provide your own implementation of the class to access the metadata repository. Each metadata repository access class must specify an individual set of properties to use to connect to the repository. //REVIEWERS: Should we provide an example here?//

  • Brief example of how to use the XML. You can use "User-Specified Example" below. And explain that the propeties that start with "com.foo" are implementer-defined.--Tom.ware.oracle.com 17:30, 28 June 2011 (UTC)

<property name="eclipselink.metadata-source" value="myPackage.MyClass"/>

  • And a note that says you can subclass either org.eclipse.persistence.internal.jpa.extensions.MetadataRepository or org.eclipse.persistence.internal.jpa.extensions.XMLMetadataRepository. --Tom.ware.oracle.com 17:30, 28 June 2011 (UTC)


Examples

//REVIEWERS: Can we say something more about these examples to explain them? What? And should all this information be moved up to Configuring persistence.xml?//

  • XML File examples is covered above and could possibly be removed here.--Tom.ware.oracle.com 17:32, 28 June 2011 (UTC)

XML File Example

<property name="eclipselink.metadata-source" value="XML"/>
<property name="eclipselink.metadata-source.xml.url" value="foo://bar"/>


User-Specified Example

<property name="eclipselink.metadata-source" value="com.foo.MetadataRepository"/>
<property name="com.foo.MetadataRepository.location" value="foo://bar"/>
<property name="com.foo.MetadataRepository.extra-data" value="foo-bar"/>

Elug note icon.png

Note: Use [RefreshMetadata()] to refresh the metadata repository.

--Tom.ware.oracle.com 17:35, 28 June 2011 (UTC) //REVIERWERS: Should that note on refresh metadata be included? Should something more be said about it?//

Eclipselink-logo.gif
Version: DRAFT
Other versions...

Elug previous icon.png link=‎
link=‎
link=‎ EclipseLink Home

JPA User Guide: Elug guide icon.pngTable of Contents, Search elug.pngSearch

How to contribute to this guide...
  • refreshMetadata() is important. We should indicate that if you change the metadata and you want an EntityManager based on the new metadata, you call refreshMetadata on the EntityManagerFactory and then the next EntityManager you get will be based on the new metadata. Additionally, refreshMetadata takes a Map of properties and that map of properties can be used to override the properties previously defined for the metadata-source.--Tom.ware.oracle.com 17:36, 28 June 2011 (UTC)