[hibernate-dev] Naming and "naming strategies"

Gunnar Morling gunnar at hibernate.org
Wed Jan 14 12:14:06 EST 2015


2015-01-14 16:19 GMT+01:00 Steve Ebersole <steve at hibernate.org>:

> Something like:
>
>
> public interface ImplicitNamingStrategy {
>   public Identifier determinePrimaryTableName(ImplicitEntityNameSource
> source);
>
>   public Identifier determineJoinTableName(ImplicitJoinTableNameSource
> source);
>
>   public Identifier
> determineCollectionTableName(ImplicitCollectionTableNameSource
> source);
>
>   public Identifier
> determineDiscriminatorColumnName(ImplicitDiscriminatorColumnNameSource
> source);
>
>     public Identifier
> determineTenantIdColumnName(ImplicitTenantIdColumnNameSource
> source);
>
>   public Identifier
> determineAttributeColumnName(ImplicitAttributeColumnNameSource
> source);
>
>   public Identifier
> determineCollectionJoinColumnName(ImplicitCollectionJoinColumnNameSource
> source);
>
>     ...
> }
>
>
> The sources are simply parameter objects providing access to information
> needed to determine the implicit name.  For example:
>
> /**
>  * Defines the source for entity naming.  Between legacy Hibernate
> requirements and
>  * JPA requirements this is, unfortunately, multi-sourced.  This contract
> allows
>  * access to all source values.
>  *
>  * @author Steve Ebersole
>  */
> public interface ImplicitEntityNamingSource {
>     /**
>      * The FQN of the entity class.  Note, this may be {@code null} in the
> case
>      * of (non-JPA-compliant) dynamic entities).
>   *
>      * @return The entity class FQN, or {@code null} if a dynamic entity.
>   */
>   public String getEntityClassName();
>
>   /**
>      * Get the explicitly specified Hibernate entity name.  The Hibernate
> name is
>   * very much different from the JPA concept of entity name.
>   *
>   * @return The explicitly specified entity name
>   */
>   public String getExplicitEntityName();
>
>   /**
>   * The Hibernate entity name.  This might be either:<ul>
>   *     <li>The explicitly specified entity name, if one</li>
>   *     <li>The unqualified entity class name if no entity name was
> explicitly specified</li>
>   * </ul>
>   *
>    * @return The Hibernate entity name
>   */
>   public String getEntityName();
>
>   /**
>  * The JPA-specific entity name.  See {@link
> javax.persistence.Entity#name()} for details.
>      *
>   * @return The JPA entity name, if one was specified.  May return {@code
> null} if one
>   * was not explicitly specified.
>   */
>   public String getJpaEntityName();
> }
>
> etc...
>
> And then:
>
> public interface PhysicalNamingStrategy {
>     public Identifier toPhysicalCatalogName(Identifier name);
>
>     public Identifier toPhysicalSchemaName(Identifier name);
>
>     public Identifier toPhysicalTableName(Identifier name);
>
>     public Identifier toPhysicalColumnName(Identifier name);
> }
>
>
So why is PhysicalNamingStrategy returning Identifiers and not Strings? I
think I find the double usage of Identifier for logical names (or
"components" thereof) and physical names somewhat irritating. As the
physical name I'd have expected just the "rendered" String as to be passed
to the driver.

I think ultimately it makes sense to pass some additional information
> into PhysicalNamingStrategy to give access to Dialect, etc.
>

Interesting; As we had already discussed recently, that raises the question
of how to evolve the interface in a compatible way.

Java 8's default methods of course help, but until we can rely on that, I
find using abstract classes rather than interfaces attractive for such
contracts. With these, a method such as void
initialize(SomeInitializationContext) can be easily added, and
implementations can override it in a future version if they wish. Or you
foresee some sort of context parameter on the actual methods of the
contract.


>
> On Wed, Jan 14, 2015 at 4:38 AM, Hardy Ferentschik <hardy at hibernate.org>
> wrote:
>
> > Hi,
> >
> > +1 for ImplicitNamingStrategy and PhysicalNamingStrategy
> > What would be the contract of these strategies?
> >
> > I don't think LogicalNamingStrategy is necessary. I think this might
> > just get too complicated for a user. Also, iiuc the logical name is for
> > internal lookups.
> >
> > +1 for actual identifier classes. I think the code would become easier to
> > understand
> > and hopefully safer with these typed classes. I liked this approach when
> > working
> > on the metamodel branch. I would, however, not make it an interface. I
> > also see
> > this as a pre-mature optimisation
> >
> > > Since JPA does not say what is legal/illegal for the @Column.table
> > > attribute, it is feasible for us to allow @Column.table to contain the
> > > catalog/schema information in these cases as a selector..
> >
> > What exactly do you mean with 'selector'?
> >
> > --Hardy
> >
> >
> >
> > On Tue, Jan 13, 2015 at 12:43:37PM -0600, Steve Ebersole wrote:
> > > As I am working on 5.0, one of the things I am trying to accomplish is
> to
> > > make the handling of table/column names more consistent and better
> > > defined.  The first step in that is to properly define the terms used
> > often
> > > throughout the codebase.
> > >
> > > The first level of naming is the "given" name of a table/column.  The
> > given
> > > name might be:
> > > * explicit - explicitly specified by the user, as in @Table(
> > > name="explicit_name" )
> > > * implicit - not explicitly specified by the user and thus implicitly
> > > determined (by JPA rules, "naming strategy", etc).
> > >
> > > Next, we have a logical name which is a normalized form of the "given"
> > > name.  This is the form used to reference tables/columns internally.
> > E.g.,
> > > its how we resolve @Column(..., table="xyz").  More on this form later.
> > >
> > > Finally we have the physical name of the thing, which is the actual
> name
> > of
> > > the table/column in the database.  Again, this is generally a
> > normalization
> > > of the given name based on Dialect, "naming strategy", etc.
> > >
> > > Today, we have a very messy concept called a NamingStrategy.  I say it
> is
> > > messy because it tries to combine unrelated concerns.  So I still plan
> to
> > > split this as I have outlined elsewhere into:
> > > 1) ImplicitNamingStrategy
> > > 2) PhysicalNamingStrategy
> > >
> > > Which brings up my first question to y'all.  Do we need a contract for
> > > LogicalNamingStrategy?  As I have said, the logical names are the
> things
> > > used to resolve references.  Allowing people to plug in custom
> strategies
> > > for how that normalization works could be very dangerous.  But even
> more
> > > than that, is it really interesting to be able to hook into that
> process?
> > >
> > > Historically, these names are all represented by String.  So I also
> > propose
> > > to shift this to use that Identifier class we developed for the
> metamodel
> > > redesign.  For those that may be unfamiliar, it essentially combines
> the
> > > String name with a "quoted" boolean:
> > >
> > > public class Identifier {
> > >   private final String text;
> > >   private final boolean isQuoted;
> > >     ...
> > > }
> > >
> > > Table names, then, are an aggregation of 3 Identifiers: one for
> catalog,
> > > one for schema, one for table name.  Same for named constraints
> > > (ultimately, which is part of a improvement for 6.0 to allow indexes,
> > > constraints, etc to be created in a separate schema from tables).
> > >
> > > Since a major goal for 5.0 is to continue to use the
> > org.hibernate.mapping
> > > package as the representation of the mapping information, we obviously
> > want
> > > to minimize changes there to only what is completely essential.  To
> that
> > > end, if we are going to use Identifier over String stuff in the
> > > org.hibernate.mapping package will need to deal with both; internally
> > they
> > > will hold the Identifier and use that to implement the String-based
> > > name-related methods they expose.
> > >
> > > Lastly I wanted to discuss the details of the logical names.  For
> tables,
> > > we currently qualify the table name with the catalog/schema info.
> There
> > is
> > > a mismatch in this regard when it comes to remaining a pure JPA
> > > implementation.  Consider @Column( ..., table="some_table").
> Ultimately
> > we
> > > need to be able to qualify that with catalog/schema in order to be able
> > to
> > > construct a matching logical name (to be able to pair that with the
> > > referenced org.hibernate.mapping.Table later).  This is trivial when
> > table
> > > names are unique across all the catalogs/schemas (when there is only
> one
> > > "some_table" in all the mapped catalogs/schemas).  But is poses a
> problem
> > > when the same table name is used from different schemas (e.g., when
> > > "some_table" is mapped from both "schema1" and "schema2").  So we have
> a
> > > choice.  Since JPA does not say what is legal/illegal for the
> > @Column.table
> > > attribute, it is feasible for us to allow @Column.table to contain the
> > > catalog/schema information in these cases as a selector.  The only
> other
> > > option I can see is to define a limitation that says that a table name
> > must
> > > be unique for a given entity across all catalogs/schemas.  I don't
> think
> > > that is generally a restrictive limitation.  What are y'alls thoughts?
> > > Perhaps this is one argument for allowing pluggable
> > LogicalNamingStrategy?
> > > _______________________________________________
> > > hibernate-dev mailing list
> > > hibernate-dev at lists.jboss.org
> > > https://lists.jboss.org/mailman/listinfo/hibernate-dev
> >
> _______________________________________________
> hibernate-dev mailing list
> hibernate-dev at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/hibernate-dev
>


More information about the hibernate-dev mailing list