Persistence Mapping

来源:互联网 发布:形状优化设计 编辑:程序博客网 时间:2024/05/17 07:55

4.Persistence Mapping

It is needed to do Object Relational Mapping which is a mapping Persistence objects with specific table by using Hibernate. This page does not cover what is needed to map one object with one table, instead will have a look at how to map objects in Association and Inheritance relation with one table. (*Note. For information on what is needed to map one object with one table, refer to Mapping XML File under Hibernate.)

4.1.Persistence Mapping - Association

In this page, let's take a look at mapping method by Association type between two classes. In particular, on One to Many Mapping which will be used most frequently in object modeling, we will analyze central to various Collection mapping methods and sample code for inverse and cascade, main properties of Collection.

4.1.1.One to One Mapping

There are many ways of mapping the relationship of two classes in "A:B = 1:1" relationship. One of them is mapping reference relationship of two classes based on same Primary Key.

The figure on the left is a class diagram," Foo : Bar = 1:1" and expresses one-way reference relation. Like ERD in the right-top figure, it can be mapped with TBL_FOO and TBL_BAR respectively, and does not require special column addition but uses the same Primary Key. How to define such mapping relationship in Hibernate Mapping XML file is as shown in the bottom of the right figure. In this figure, each class and property of Foo and Bar is defined by using class tag. And for reference relation between the two classes, the party which refers uses one-to-one and specifies class and table in reference relation.

4.1.2.One to Many Mapping

When mapping two classes in "A:B = 1:m" relation, B is basically in Collection type. In One to Many Mapping, we will have a look at how to define Hibernate Mapping XML file based on sample and various Collection types supported in Hibernateand inverse and cascade, which are important properties of Collection.

The figure on the left is a class diagram," Foo : Bar = 1:1" and expresses one-way reference relation. Like ERD on the top of the right figure, it can be mapped with TBL_FOO and TBL_BAR respectively, and TBL_BAR table requires Foreign Key for TBL_FOO table. How to define such mapping relationship in Hibernate Mapping XML file is as shown in the bottom of the right figure. In this figure, each class and property of Foo and Bar is defined by using class tag. In addition, by using set tag, Foo expresses Collection on Bar class. In addition, in set tag, one-to-many tag is used and relation of two objects are specified and Foreign Key column is specified through key tag. For information on how to define Hibernate Mapping on "1:m" one-way relation, refer to Country.hbm.xml and Movie.hbm.xml which express "Country : Movie = 1:m" one-way relation. If mapping information is added to B in Hibernate Mapping XML, two-way reference becomes also possible.

<class name="Bar" table="TBL_BAR">    …    <many-to-one name="TBL_FOO" class="Foo" column="FOO_ID"/></class>

For information how to define Hibernate Mapping XML in 1:m two-way relation, refer to Country.hbm.xml and Movie.hbm.xml which express two-way relation of "Country : Movie = 1:m".

4.1.2.1.Collection Mapping

As mentioned above, when mapping two classes in 1:m relation, B is basically in Collection type. There are various Collection types supported in Hibernate in addition to "set".

  • set : java.util.Set type. Defines by using <set>. It is not possible to know the order of saving object, and double saving of the same object is not allowed (Using HashSet). The following is an example of Hibernate Mapping XML and source code which define Collection object by using set tag.

    1. Hibernate Mapping XML<class name="org.anyframe.sample.model.unidirection.relation.collection.CountryWithSet"         table="COUNTRY_SET" lazy="true" schema="PUBLIC">    ...    <set name="movies" inverse="true" cascade="save-update">        <key>            <column name="COUNTRY_CODE" length="12" />        </key>        <one-to-many class="org.anyframe.sample.model.bidirection.Movie" />    </set></class>
    2. CountryWithSet.javapublic class CountryWithSet implements java.io.Serializable {    private String countryCode;    private String countryId;    private String countryName;    private Set movies = new HashSet(0);    ...}

  • list : java.util.List type. This defines by using <list>. In the case of List type, it is possible to know the order of saving object, and special definition of index column is needed if you want to keep the saving order to table. For special column to save the object saving order, use <list-index>under <list>>(Using ArrayList). The following is an example of Hibernate Mapping XML and source code which define Collection object by using list tag.

    1. Hibernate Mapping XML<class name="org.anyframe.sample.model.unidirection.relation.collection.CountryWithList"         table="COUNTRY_LIST" lazy="true" schema="PUBLIC">    ...    <list name="movies" cascade="save-update">        <key>            <column name="COUNTRY_CODE" length="12" />        </key>        <list-index column="MOVIE_IDX"/>        <one-to-many class="org.anyframe.sample.model.unidirection.Movie" />    </list></class>
    2. CountryWithList.javapublic class CountryWithList implements java.io.Serializable {    private String countryCode;    private String countryId;    private String countryName;    private List movies = new ArrayList(0);    ...}

  • bag : 'java.util.Collection' type uses and defines <bag> or <idbag>. It is not possible to know the order of saving object, but double saving of the same object is allowed. Internally uses List but does not use index value (Using ArrayList). In addition, Bag is similar to Set, but is superior to Set in terms of performance in that it can add new object to the relevant Collection even without loading all Collections. The following is an example of Hibernate Mapping XML and source code which define Collection object by using <bag>.

    1. Hibernate Mapping XML<class name="org.anyframe.sample.model.unidirection.relation.collection.CountryWithBag"         table="COUNTRY_BAG" lazy="true" schema="PUBLIC">    ...    <bag name="movies" inverse="true" cascade="save-update">        <key>            <column name="COUNTRY_CODE" length="12" />        </key>        <one-to-many class="org.anyframe.sample.model.unidirection.Movie" />    </bag></class>
    2. CountryWithBag.javapublic class CountryWithBag implements java.io.Serializable {    private String countryCode;    private String countryId;    private String countryName;    private Collection movies = new ArrayList(0);    ...}

    The following is an example of Hibernate Mapping XML and source code which define Collection object by using <idbag> Unlike bag, idbag guarantees order. And unlike other Collection mapping methods in One to Many relation, it should define in value type by using composite-element tag.

    1. Hibernate Mapping XML<class name="org.anyframe.sample.model.unidirection.relation.collection.CountryWithIdBag"         table="COUNTRY_IDBAG" lazy="true" schema="PUBLIC">    ...    <idbag name="movies" table="MOVIE">         <collection-id column="id" type="java.lang.String">             <generator class="uuid"/>         </collection-id>         <key column="COUNTRY_CODE" />        <composite-element class="org.anyframe.sample.model.unidirection.Movie">             <property name="title" type="string">                <column name="TITLE" length="100" not-null="true" />            </property>            <property name="director" type="string">                <column name="DIRECTOR" length="10" not-null="true" />            </property>            <property name="releaseDate" type="date">                <column name="RELEASE_DATE" length="0" />            </property>        </composite-element>    </idbag> </class>
    2. CountryWithIdBag.javapublic class CountryWithIdBag implements java.io.Serializable {    private String countryCode;    private String countryId;    private String countryName;    private Collection movies = new ArrayList(0);...}

  • map : java.util.map type. This defines (key, value) pair by using <map> (Using HashMap). The following is an example of Hibernate Mapping XML and source code which define Collection object by using <map>.

    1. Hibernate Mapping XML<class name="org.anyframe.sample.model.unidirection.relation.collection.CountryWithMap"         table="COUNTRY_MAP" lazy="true" schema="PUBLIC">    ...    <map name="movies" cascade="save-update">        <key>            <column name="COUNTRY_CODE" length="12" />        </key>        <map-key column="MOVIE_MAP_KEY" type="string"/>        <one-to-many class="org.anyframe.sample.model.unidirection.Movie" />    </map></class>
    2. CountryWithMap.javapublic class CountryWithMap implements java.io.Serializable {    private String countryCode;    private String countryId;    private String countryName;    private Map movies = new HashMap(0);    ...}

  • StoredSet, StoredMap : Uses <set>, <map> as it is, but defines sorting method by using attribute 'sort'(using TreeSet, TreeMap).

You can see how to use above-mentioned Collection by type and how they differ through HibernateCollectionMapping.java code.

4.1.2.2.Inverse, Cascade property

'inverse' and 'cascade' are one of properties that have important mean in definition, and have the following meaning.

  • inverse : Property that defines the option on determine the responsibility of the relation between objects. In other words, it is for defining role of owner for one part and of sub role for the other.

  • cascade : Property to define the option on whether or not to transfer the CUD on parent object to child object.

Now let's have a look at how string executed by inverse and cascade property change by property definition and learn the properties of inverse and cascade in detail.

  • One-way 1:m relation

    1. inverse="false", cascade="false"

      public void addCountryMovieWithoutInverseCascade() throws Exception {    // 1. make init data    newSession("anyframe/core/hibernate/inverse/unidirection/"            + "hibernate-without-inversecascade.cfg.xml");    Country country = makeCountry();    Movie movie = makeMovie();    // 2. try to make a relation between country and movie    /* #1 */ country.getMovies().add(movie);    // 3. try to insert a country, movie    /* #2 */ session.save(country);    /* #3 */ session.save(movie);    closeSession();    ...}

      As a result of executing addCountryMovieWithoutInverseCascade() method, INSERT string for registering new Country information and Movie information is executed by code #2 and #3. And, as the inverse property value on Movie Collection was set "false" at Country, Update string for setting relation between Country and Movie is executed once more by code #1. In other words, three strings are performed as the following.

      insert into PUBLIC.COUNTRY    (COUNTRY_ID, COUNTRY_NAME, COUNTRY_CODE)         values ('KR', 'Korea', 'COUNTRY-0001') insert into PUBLIC.MOVIE    (TITLE, DIRECTOR, RELEASE_DATE, MOVIE_ID)         values ('My Sassy Girl', 'Jaeyong Gwak', 2001-07-27, 'MV-00001') update PUBLIC.MOVIE    set COUNTRY_CODE='COUNTRY-0001' where MOVIE_ID='MV-00001'

    2. inverse="true", cascade="false"

      public void addCountryMovieWithoutCascade() throws Exception {    // 1. make init data    newSession("anyframe/core/hibernate/inverse/unidirection/"            + "hibernate-without-cascade.cfg.xml");    Country country = makeCountry();    Movie movie = makeMovie();    // 2. try to make a relation between country and movie    country.getMovies().add(movie);// no effect code!!    // 3. try to insert a country, movie    /* #1 */ session.save(country);    /* #3 */ // movie.setCountryCode(country.getCountryCode());    /* #2 */ session.save(movie);    closeSession();    ...}

      As a result of executing addCountryMovieWithoutCascade() method, INSERT string for registering new Country information and Movie information is executed by code #1 and #2. In addition, in case of 'inverse="true"', Movie should see the relation information with the related Country information, but which is not also possible due to one-way relation of 'Country -> Movie'. Hence, there may be information omission between Country and Movie. In this case, define special property for COUNTRY_CODE column within Movie Mapping File as in code #3. And by directly setting countryCode when registering Movie, you can maintain the relation between two objects. The following is a string performed after executing addCountryMovieWithoutCascade() method.

      insert into PUBLIC.COUNTRY    (COUNTRY_ID, COUNTRY_NAME, COUNTRY_CODE)         values ('KR', 'Korea', 'COUNTRY-0001') insert into PUBLIC.MOVIE    (TITLE, DIRECTOR, RELEASE_DATE, MOVIE_ID)         values ('My Sassy Girl', 'Jaeyong Gwak', 2001-07-27, 'MV-00001')

    3. inverse="false", cascade="true"

      public void addCountryMovieWithoutInverse() throws Exception {    // 1. make init data    newSession("anyframe/core/hibernate/inverse/unidirection/"            + "hibernate-without-inverse.cfg.xml");    Country country = makeCountry();    Movie movie = makeMovie();    // 2. try to make a relation between country and movie    /* #2 */ country.getMovies().add(movie);    // 3. try to insert a country    /* #1 */ session.save(country);    closeSession();    ...}

      As a result of executing addCountryMovieWithoutInverse() method, INSERT string for registering new Country information and Movie information is executed by code #1 and cascade property value. And, as inverse property value was set "false" for Movie Collection in Country, UPDATE string is executed once more for setting relation of Country and Movie by code #2. In other words, three strings are performed as the following.

      insert into PUBLIC.COUNTRY    (COUNTRY_ID, COUNTRY_NAME, COUNTRY_CODE)         values ('KR', 'Korea', 'COUNTRY-0001') insert into PUBLIC.MOVIE    (TITLE, DIRECTOR, RELEASE_DATE, MOVIE_ID)         values ('My Sassy Girl', 'Jaeyong Gwak', 2001-07-27, 'MV-00001') update PUBLIC.MOVIE    set COUNTRY_CODE='COUNTRY-0001' where MOVIE_ID='MV-00001'

    4. inverse="true", cascade="true"

      public void addCountryMovie() throws Exception {    // 1. make init data    newSession("anyframe/core/hibernate/inverse/unidirection/hibernate.cfg.xml");    Country country = makeCountry();    Movie movie = makeMovie();    // 2. try to make a relation between country and movie    country.getMovies().add(movie); // no effect code!!    // 4. try to insert a country    /* #2 */ // movie.setCountryCode(country.getCountryCode());    /* #1 */session.save(country);    closeSession();    ...}

      As a result of executing addCountryMovie() method, INSERT string for registering new Country information and Movie information is executed by code #1 and cascade property value. In addition, in case of 'inverse="true"', Movie should see the relation information with the related Country information, but which is not also possible due to one-way relation of 'Country -> Movie'. Hence, there may be information omission between Country and Movie. In this case, define special property for COUNTRY_CODE column within Movie Mapping File as in code #2. And by directly setting countryCode when registering Movie, you can maintain the relation between two objects. The following is a string performed after executing addCountryMovie() method.

      insert into PUBLIC.COUNTRY    (COUNTRY_ID, COUNTRY_NAME, COUNTRY_CODE)         values ('KR', 'Korea', 'COUNTRY-0001') insert into PUBLIC.MOVIE    (TITLE, DIRECTOR, RELEASE_DATE, MOVIE_ID)         values ('My Sassy Girl', 'Jaeyong Gwak', 2001-07-27, 'MV-00001')

    For the whole test code including the code mentioned in the table, refer to HibernateUnidirectionInverseCascade.java.

  • Two-way 1:m relation

    1. inverse="false", cascade="false"

      public void addCountryMovieWithoutInverseCascade() throws Exception {    // 1. make init data    newSession("anyframe/core/hibernate/inverse/bidirection/            hibernate-without-inversecascade.cfg.xml");    Country country = makeCountry();    Movie movie = makeMovie();    // 2. try to make a relation between country and movie    /* #3 */ country.getMovies().add(movie);    // 3. try to insert a country, movie    /* #1 */ session.save(country);    /* #2 */ session.save(movie);    closeSession();}

      As a result of executing addCountryMovieWithoutInverseCascade() method, INSERT string for registering new Country information and Movie information is executed by code #1 and #2. In addition, in case of 'inverse="false"', UPDATE string is additionally executed for setting COUNTRY_CODE information of MOVIE table from null to 'COUNTRY-0001' by code #3. In other words, three strings are executed as the following.

      insert into PUBLIC.COUNTRY    (COUNTRY_ID, COUNTRY_NAME, COUNTRY_CODE)         values ('KR', 'Korea', 'COUNTRY-0001')insert into PUBLIC.MOVIE    (COUNTRY_CODE, TITLE, DIRECTOR, RELEASE_DATE, MOVIE_ID)         values (null, 'My Sassy Girl', 'Jaeyong Gwak', 2001-07-27, 'MV-00001')update PUBLIC.MOVIE    set COUNTRY_CODE='COUNTRY-0001' where MOVIE_ID='MV-00001'

    2. inverse="true", cascade="false"

      public void addCountryMovieWithoutCascade() throws Exception {    // 1. make init data    newSession(        "anyframe/core/hibernate/inverse/bidirection/hibernate-without-cascade.        cfg.xml");    Country country = makeCountry();    Movie movie = makeMovie();    // 2. try to make a relation between movie and country    /* #4 */ // country.getMovies().add(movie);    /* #3 */ movie.setCountry(country);    // 3. try to insert a country, movie    /* #1 */ session.save(country);    /* #2 */ session.save(movie);    closeSession();}

      As a result of executing addCountryMovieWithoutCascade() method, INSERT string for registering new Country information and Movie information is executed by code #1 and #2. And given the case of 'inverse="true"' and two-way relation of Country <-> Movie, CountryCode information expressing the relation of Country and Movie is set at Movie INSERT through code #3. In addition, because of cascade="false", code #4 is not necessary.

      In the code above, unlike one-way relation, as Country and Movie relation information was already set at Movie INSERT, Relation information is not omitted. In addition, unlike in the case of inverse="false", as special UPDATE query for special relation information setting is not needed, it is superior in terms of performance.

      The following is a string performed as a result of executing addCountryMovieWithoutCascade() method.

      insert into PUBLIC.COUNTRY    (COUNTRY_ID, COUNTRY_NAME, COUNTRY_CODE)     values ('KR', 'Korea', 'COUNTRY-0001'insert into PUBLIC.MOVIE    (COUNTRY_CODE, TITLE, DIRECTOR, RELEASE_DATE, MOVIE_ID)     ('COUNTRY-0001', 'My Sassy Girl', 'Jaeyong Gwak', 2001-07-27, 'MV-00001')

    3. inverse="false", cascade="true"

      public void addCountryMovieWithoutInverse() throws Exception {    // 1. make init data    newSession(        "anyframe/core/hibernate/inverse/bidirection/hibernate-without-inverse.cfg.xml");    Country country = makeCountry();    Movie movie = makeMovie();    // 2. try to make a relation between country and movie    /* #2 */ country.getMovies().add(movie);    /* #3 */ // movie.setCountry(country); // no effect code!!     // 3. try to insert a country    /* #1 */ session.save(country);    closeSession();}

      As a result of executing addCountryMovieWithoutInverse() method, INSERT string for registering new Country information and Movie information is executed by code #1 and cascade property. And, as inverse property value was set "false" for Movie Collection in Country, UPDATE string is executed once more for setting relation of Country and Movie by code #2. In addition, as code #2 affects the relation setting, code #3 is not necessary. In other words, three strings are executed as the following.

      insert into PUBLIC.COUNTRY    (COUNTRY_ID, COUNTRY_NAME, COUNTRY_CODE)         values ('KR', 'Korea', 'COUNTRY-0001')insert into PUBLIC.MOVIE    (COUNTRY_CODE, TITLE, DIRECTOR, RELEASE_DATE, MOVIE_ID)         values (null        , 'My Sassy Girl', 'Jaeyong Gwak', 2001-07-27, 'MV-00001')update PUBLIC.MOVIE        set COUNTRY_CODE='COUNTRY-0001' where MOVIE_ID='MV-00001'

    4. inverse="true", cascade="true"

      public void addCountryMovie() throws Exception {    // 1. make init data    newSession("anyframe/core/hibernate/inverse/bidirection/            hibernate.cfg.xml");    Country country = makeCountry();    Movie movie = makeMovie();    // 2. try to make a relation between country and movie    /* #2 */ country.getMovies().add(movie);    // 3. try to make a relation between movie and country    /* #3 */ movie.setCountry(country);    // 4. try to insert a country    /* #1 */ session.save(country);    closeSession();}

      As a result of executing addCountryMovie() method, INSERT string for registering new Country information and Movie information is executed by code #1 and cascade property. And given the case of 'inverse="true"' and two-way relation of Country <-> Movie, CountryCode information expressing the relation of Country and Movie is set at Movie INSERT through code #3.

      In the code above, unlike one-way relation, as Country and Movie relation information was already set at Movie INSERT, Relation information is not omitted. In addition, unlike in the case of inverse="false", as special UPDATE query for special relation information setting is not needed, it is superior in terms of performance.

      The following is a string executed after the execution of addCountryMovie() method.

      insert into PUBLIC.COUNTRY    (COUNTRY_ID, COUNTRY_NAME, COUNTRY_CODE)         values ('KR', 'Korea', 'COUNTRY-0001')insert into PUBLIC.MOVIE    (COUNTRY_CODE, TITLE, DIRECTOR, RELEASE_DATE, MOVIE_ID)         values ('COUNTRY-0001', 'My Sassy Girl', 'Jaeyong Gwak', 2001-07-27, 'MV-00001')

    For the whole test code including the code mentioned in the table, refer to HibernateBidirectionInverseCascade.java.

4.1.3.Many to Many Mapping

In case that the relation of two classes is m:n, is it mapped by defining Association table which has each Foreign Key.

The figure on the left is a class diagram, "User : Role = m:n" and expresses one-way reference relation. Like ERD on the top of the right figure, it can be mapped with TBL_USER and TBL_ROLE respectively, and requires TBL_USER_ROLE, Association table which has Primary Key of each table as Foreign Key. How to define such mapping relationship in Hibernate Mapping XML file is as shown in the bottom of the right figure. In this figure, each class and property of User and Role is defined by using class tag. User defines Role class of Collection format by using set tag. And related table defines TBL_USER_ROLE which is an Association table. In addition, in set tag, many-to-many tag is used and relation of two objects are specified and Foreign Key column is specified through key tag. For information on how to define Hibernate Mapping XML on "m:n" two-way relation, refer to Category.hbm.xml and Movie.hbm.xml which expresses " Category : Movie = m:n " two-way relation. Use <many-to-many> at both <class> for setting two-way m-n relation setting, but it is recommended that one part in charge of relation define "inverse=true" so that mapping can be handled by one part. For how to define Hibernate Mapping XML on two-way m:n relation, refer to Category.hbm.xml and Movie.hbm.xml which express the two-way relation of "Category : Movie = m:n".

4.2.Persistence Mapping - Inheritance

In this page, let's take a close look at how to map various classes that take part in inheritance.

4.2.1.Table per Class Hierarchy

Refers to mapping method which maps all Parent/Child classes taking part in inheritance relation in one table and additionally mapping special Discriminator column to classify the type of Child class.

The top-left figure is a class diagram, where there exist Guest, Member, Staff classes which inherited User class. And the bottom-left figure is ERD, which maps User, Guest, Member, Staff class in one table named TBL_USER. How to define such mapping relationship in Hibernate Mapping XML file is as shown in the bottom of the right figure. In this figure, it is needed define User class information by using class tag, and to classify child class type by using discriminator tag under, discrimintor column which is specially needed must be additionally defined. In addition, by using subclass tag under, sub-class which inherits User class and the property are to defined. In this case, value of Discrimintor for each subclass must be defined. The following is the merits and demerits of Table per Class Hierarchy mapping.

[Merits]

  • Easy to develop as no special Join handling is needed.

  • Overhead for inheritance control minimized.

[Demerits]

  • Cannot define NOT NULL constraints based on specific table.

  • When creating sub-class which has additional variable, it is inevitable to change the table structure.

  • Increased number of columns of management target and those with NULL value.

  • Need to define special column to classify subclass type regardless of the feature of the domain.

If you don't want to make special Discriminator column, you can use 'formula' property as the following. This refers to defining Discriminator value through calculation of specific column value. In the example below, if the value of DEPT_ID is NOT NULL, the consequent object will be staff as Discriminator value is 'STAFF'.

<discriminator formula="CASE WHEN DEPT_ID IS NOT NULL THEN 'STAFF'         …"        type="string"/>

4.2.2.Table per Subclass

Maps all Parent/Child classes in inheritance relation with each table, but all sub-tables share Primary Key same to parent class.

The top-left figure is a class diagram, where there exist Guest, Member, Staff classes which inherited User class. And the bottom-left figure is ERD, which maps all classes with TBL_USER, TBL_GUEST, TBL_MEMBER, TBL_STAFF table. How to define such mapping relationship in Hibernate Mapping XML file is as shown in the bottom of the right figure. In this figure, it is needed define User class information by using joined-subclass, and to classify child class type by using discriminator tag under, discriminator column which is specially needed must be additionally defined. The following is the merits and demerits of Table per Class Hierarchy mapping.

[Merits]

  • The closest object oriented mapping. The most natural mapping method when sub-class has many properties.

  • Can define NOT NULL Constraints based on specific table.

  • When using Hibernate, special Discriminator column for classifying sub-class type is not needed.

[Demerits]

  • As each table needs to join at table search, performance issue can arise as hierarchy becomes more complicated.

  • If data is added directly from outside instead of via Hibernate, the data may not be coherent.

※ Note that in case of requesting search through parent class without specifying special child class to search (namely, when performing query by using parent class),Outer JOIN is performed by all tables in inheritance to find the type of the relevant class as Hibernate has no information on the actual to-search class, which leads to weaker performance.

(* If special child class is specified, Inner JOIN is executed.)

4.2.3.Table per Concrete Class

Refers to a way of mapping all Concrete classes in inheritance with each table. All mapped tables need to be repeatedly defined with property of parent table. If parent class is an abstract class, no special table definition is needed, but abstract must be defined as true.

The top-left figure is a class diagram, where there exist Guest, Member, Staff classes which inhersted User class. And the bottom-left figure is ERD, which maps tables named TBL_GUEST, TBL_MEMBER, TBL_STAFF. How to define such mapping relationship in Hibernate Mapping XML file is as shown in the bottom of the right figure. In this figure, User class information is defined by using class tag, and abstract property of User class is defined as true. In addition, by using union-subclass tag under, each sub-class and property are defined. The following is the merits and demerits of Table per Concrete Class mapping.

[Merits]

  • Can define NOT NULL Constraints based on specific table.

  • Useful if used when Polymorphic Query is not necessary. (* Polymorphic Query : Search for all classes which extend or implement specific class/interface to search.)

[Demerits]

  • Note that UNION must be used at data search, but UNION is not supported in all DB.

  • Common information of upper class is repeated in each table.

  • If data is added directly from outside instead of via Hibernate, the data may not be coherent.

原创粉丝点击