users@jpa-spec.java.net

[jpa-spec users] [jsr338-experts] Re: schema generation proposed changes

From: Steve Ebersole <steve.ebersole_at_redhat.com>
Date: Sun, 29 Jul 2012 16:16:06 -0500

I have a concern about the API here. Specifically:

public void generateSchema(PersistenceUnitInfo info, Map map)
public void generateSchema(String persistenceUnitName, Map properties)

The concern is that we will potentially be parsing the mapping
information twice per deployment: once to comply with the "generate
schema" call and then again to build the EMF. Unless providers stash
away the "parsed" information in a static context, which is rather
dubious IMHO. Yes, this works in the case when the caller only wants
the schema generation to happen.

I think it is more a general concern with the bootstrapping process.

This actually falls into a discussion Scott Marlow and I have been
having about provider bootstrapping. The discussion started out in
regards to container bootstrapping specifically, but I think it is
generally applicable to SE bootstrapping as well. The idea Scott and I
decided to implement specific to JBoss/Hibernate integration is a 2-step
bootstrapping process. Not sure if that is something that we want to
address in 2.1, but I think it really needs to be addressed at some
point. Scott had planned on writing up a proposal for this so I don;t
want to steal his thunder, but I did want to raise this concern in
regards to this proposal. The basic premise behind the 2-step process
is that the first step returns a delegate capable of building an
EntityManagerFactory given the current set of inputs (Map and
persistenceUnitName/persistenceUnitInfo); that first step would have
certain restrictions on what it could do and what it could access. In
this scenario, we could ask this "delegate capable of building an
EntityManagerFactory" to "generateSchema".

This works with both cases of the schema generation happening as part of
the EMF starting and in the case of the caller only wanting schema
generation to happen. And more specifically in that first case it works
without double parsing the mapping information.

I really do understand the desire to avoid API changes. But I also know
that sometimes they do need to change. I think this is a good example
of that. The initial bootstrapping API was never designed with this new
feature in mind (how could it have been). In fact, in the EE case this
2-step process makes sense even without considering this new feature.


Also, trying to look forward again, even though we currently only
support create/drop the initial discussion discussed "schema migration"
as well. I wonder if in anticipation of that possibly being added in a
later spec revision we might want to name these methods something other
than "generate" (really it does not even fit in the DROP case). Maybe
"manageSchema"?


On 07/23/2012 06:55 PM, Linda DeMichiel wrote:
> Here's an updated version of my earlier schema generation proposal,
> broken out as to proposed spec changes. You should hopefully find
> this considerably more flexible and detailed than the earlier draft.
>
> -Linda
>
> ----------------------------
>
> Proposed spec changes:
>
>
> New Section: Schema Generation [to follow section 9.3]
>
> Schema generation may either happen prior to application deployment or
> when the entity manager factory is created as part of the application
> deployment and initialization process.
>
> * In Java EE environments, the container may call the
> PersistenceProvider generateSchema method separately from and/or
> prior to the creation of the entity manager factory for the
> persistence unit, or the container may pass additional
> information to the createContainerEntityManagerFactory call to
> cause schema generation to happen as part of the entity manager
> factory creation and application initialization process. The
> information passed to these methods determines whether the
> generation of schemas and/or tables occurs directly in the target
> database, or whether DDL scripts for schema generation are
> created, or both.
>
> * In Java SE environments, the application may call the Persistence
> generateSchema method separately from and/or prior to the creation
> of the entity manager factory or may pass information to the
> createEntityManagerFactory method to cause schema generation to
> occur as part of the entity manager factory creation.
>
>
> The application may provide DDL scripts to be used for schema
> generation, and package these scripts as part of the persistence unit
> or specify URLs corresponding to the location of such scripts. In
> Java EE environments, such scripts may be executed by the container,
> or the container may direct the persistence provider to execute the
> scripts; in Java SE environments, the execution of the scripts is the
> responsibility of the persistence provider. In the absence of the
> specification of scripts, schema generation, if requested, will be
> determined by the object/relational metadata of the persistence unit.
>
>
> The following standard properties are defined for use in schema
> generation. In Java EE environments these properties are passed by
> the container in the Map argument to the PersistenceProvider
> generateSchema method or createContainerEntityManagerFactory method.
> In Java SE environments, they are passed in the Map argument to the
> Persistence generateSchema or createEntityManagerFactory method.
>
>
> javax.persistence.schema-generation-target:
>
> The schema-generation-target property specifies whether the schema
> is to be created in the database, whether scripts are to be
> generated, or both.
>
> values for this property: DATABASE, SCRIPTS, DATABASE_AND_SCRIPTS
> [Open Issue: introduce for these enum or use strings? Better names??]
>
>
> javax.persistence.schema-generation-action:
>
> The schema-generation-action property is used to specify the action
> to be taken by the persistence provider. If the
> schema-generation-target property is not specified, no action must
> be taken.
>
> values for this property: NONE, CREATE, DROP_AND_CREATE, DROP
> [Open Issue: enum strings ("none", "create", "drop-and-create",...)
>
>
> javax.persistence.create-database-schemas
>
> In Java EE environments, it is anticipated that the Java EE
> platform provider may wish to control the creation of database
> schemas rather than delegate this task to the persistence provider.
> The create-database-schemas property specifies whether the
> persistence provider is to create the database schema(s) in
> addition to creating database objects such as tables, sequences,
> constraints, etc. The value of this boolean property should be set
> to true if the persistence provider is to create schemas in the
> database or to generate DDL which is to contain "CREATE SCHEMA"
> commands. If this property is not supplied, the provider should
> not attempt to create database schemas. This property may be
> specified in Java SE environments as well.
>
>
> javax.persistence.ddl-create-script-target,
> javax.persistence.ddl-drop-script-target:
>
> If scripts are to be generated, the target locations for the
> writing of these scripts must be specified. These targets may take
> the form of either Writers or strings designating URLs. The
> persistence provider must produce both create and drop scripts if
> the corresponding DDL targets are specified. This is independent
> of whether a drop action is included in the value passed for the
> schema-generation-action property. If the schema-generation-target
> property specifies scripts and script targets are not specified,
> the IllegalArgumentException should be thrown by the provider.
>
> ddl-create-script-target: a Writer configured for the persistence
> provider for output of the DDL script or a string specifying
> the URL for the DDL script. This property should only be
> specified if scripts are to be generated.
>
> ddl-drop-script-target: a Writer configured for the persistence
> provider for output of the DDL script or a string specifying the
> URL for the DDL script. This property should only be specified
> if scripts are to be generated.
> [Suggestions for better names ??]
>
>
> javax.persistence.database-product-name,
> javax.persistence.database-product-version,
>
> If scripts are to be generated by the persistence provider and a
> connection to the target database is not supplied, the
> javax.persistence.database-product-name property must be
> specified. The value of this property should be the value
> returned for the target database by the JDBC DatabaseMetaData
> method getDatabaseProductName. If sufficient database version
> information is not included in the result of this method, the
> database-product-version property should also be specified, and
> should contain the value returned by the JDBC
> getDatabaseProductVersion method.
>
>
>
> javax.persistence.ddl-create-script-source,
> javax.persistence.ddl-drop-script-source:
>
> The ddl-create-script-source and ddl-drop-script-source properties
> are used for script execution. In Java EE container environments,
> it is generally expected that the container will be responsible
> for executing DDL scripts, although the container is permitted to
> delegate this task to the persistence provider. If DDL scripts
> are to be used in Java SE environments or if the Java EE container
> delegates the execution of scripts to the persistence provider,
> these properties must be specified. The script sources may take
> the form of either Readers or strings designating URLs.
>
> ddl-create-script-source: a Reader configured for reading of the
> DDL script or a string specifying the URL for the DDL script.
>
> ddl-drop-script-source: a Reader configured for reading of the DDL
> script or a string specifying the URL for the DDL script.
> [Suggestions for better names ??]
>
>
>
> javax.persistence.sql-load-script-source:
>
> A data load script may be supplied as part of the persistence
> unit. In Java EE container environments, it is generally expected
> that the container will be responsible for executing data load
> scripts, although the container is permitted to delegate this task
> to the persistence provider. If a load script is to be used in
> Java SE environments or if the Java EE container delegates the
> execution of the load script to the persistence provider, this
> property must be specified. The script source may take the form
> of either a Reader or a string designating a URL.
>
> sql-load-script-source: a Reader configured for reading of the SQL
> load script for database initialization or a string specifying
> the URL for the script.
>
>
>
> javax.persistence.schema-generation-connection:
>
> JDBC connection to be used for schema generation. This is intended
> for use in Java EE environments, where the platform provider may
> want to control the database privileges that are available to the
> persistence provider. This connection is provided by the container,
> and should be closed by the container when the schema generation
> request or entity manager factory creation completes. The
> connection provided must have credentials sufficient for the
> persistence provider to carry out the requested actions. If this
> property is not specified, the persistence provider should use the
> DataSource that has otherwise been provided.
>
>
>
> 9.4.1 PersistenceProvider Interface:
>
> New method:
>
> /**
> * Create database schemas and/or tables and/or create DDL
> * scripts as determined by the supplied properties
> *
> * @param info metadata for use by the persistence provider
> * @param map properties for schema generation; these
> * may also contain provider-specific properties
> * @throws PersistenceException if insufficient or inconsistent
> * configuration information is provided or if schema
> * generation otherwise fails.
> */
> public void generateSchema(PersistenceUnitInfo info, Map map)
>
>
> 9.6 Persistence Class
>
> New method:
>
> /**
> * Create database schemas and/or tables and/or create DDL
> * scripts as determined by the supplied properties
> *
> * @param persistenceUnitName the name of the persistence unit
> * @param map properties for schema generation; these may also
> * contain provider-specific properties. The values of
> * these properties override any values that may have been
> * configured elsewhere.
> * @throws PersistenceException if insufficient or inconsistent
> * configuration information is provided or if schema
> * generation otherwise fails.
> */
> public void generateSchema(String persistenceUnitName, Map properties)
>
>
> -----------------------
>
> Section 8.2.1 persistence.xml file
>
> To be added to section 8.2.1:
>
> Scripts for use in schema generation and bulk loading of data may be
> packaged as part of the persistence unit.
>
>
> To be added to Section 8.2.1.9 (properties):
>
> Scripts for use in schema generation are specified using the
> ddl-create-script and ddl-drop-script elements. A script to specify
> SQL for the bulk loading of data may be specified by the
> sql-load-script element. These scripts may be packaged as part of the
> persistence unit or designated by URL strings.
>
> <xsd:element name="database-scripts" type="database-scripts-type"
> minOccurs="0"/>
>
> <xsd:complexType name="database-scripts-type">
> <xsd:sequence>
> <xsd:element name="ddl-create-script" type="xsd:string"/>
> <xsd:element name="ddl-drop-script" type="xsd:string" minOccurs="0"/>
> <xsd:element name="sql-load-script" type="xsd:string" minOccurs="0"/>
> </xsd:sequence>
> </xsd:complexType>
>
> [Open Issue: do we want to require a drop-script if a create-script
> has been provided?]
>
> -----------
>
> Chapter 11:
>
> New annotations for use in schema generation:
>
> @Target({}) @Retention(RUNTIME)
> public @interface Index {
> String name() default "";
> String columnList();
> boolean unique() default false; // should this be here or just use
> UniqueConstraints?
> }
>
> columnList syntax follows that of the OrderBy annotation:
>
> columnList::= indexColumn [, indexColumn]*
> indexColumn::= columnName [ASC | DESC]
>
> If ASC or DESC is not specified, ASC is assumed
>
> Index[] indexes() default {};
> is to be added to Table, SecondaryTable, CollectionTable, JoinTable, and
> TableGenerator
>
>
>
> /**
> * Provides for defining a foreign key constraint or for overriding
> * or disabling the persistence provider's default foreign key
> * definition.
> */
> @Target({}) @Retention(RUNTIME)
> public @interface ForeignKey {
> String name() default "";
> String foreignKeyDefinition() default "";
> boolean disableForeignKey() default false;
> }
>
>
> The syntax used in the foreignKeyDefinition element should follow the
> SQL syntax used by the target database for foreign key constraints.
> E.g., this would likely be similar to the following:
>
> FOREIGN KEY ( <COLUMN expression> {, <COLUMN expression>}... )
> REFERENCES <TABLE identifier> [ ( <COLUMN expression> {, <COLUMN
> expression>}... ) ]
> [ ON UPDATE <referential action> ]
> [ ON DELETE <referential action> ]
>
> If disableForeignKey is specified as true, the provider must not generate
> a foreign key constraint.
>
>
> The following is to be added to JoinColumn, JoinColumns, MapKeyJoinColumn,
> MapKeyJoinColumns, PrimaryKeyJoinColumn and PrimaryKeyJoinColumns:
>
> ForeignKey foreignKey() default @ForeignKey();
>
>