简体   繁体   中英

hibernate two tables per one entity

I have one entity - User . It is described by User.class .

Hibernate creates one table per entity, so when I call session.save(user) , my data is always saved to this table.

Now I need another table for data of same User type, and I need to save my entity to that table only.

Data structure (something like this):

table users_1_table{
  string id;
  string username;
}

table users_2_table{
  string id;
  string username;
}

work with this :

session.save(user1,"users_1_table")
session.save(user2,"users_2_table")

and in result I should have user1 in users_1_table and user2 in users_2_table .

Due to system limitation I can not put these two objects in one table. (Even creating extra field is bad idea).

Can I do this without subclassing? Using programmaticaly hibernate configuration?

Preface:

This is a widely asked question even on SO, and also widely the answers are related to Subclass or actually SuperClass approach (eg [ 1 ])

Actual answer:

On these posts [ 2 ], [ 3 ] they suggest to use a xml mapping with EntityName parameter.

So, mapping with xml you don't need superclass, just give the EntityName parameter to two identical mappings.

Example Mapping:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
   <class name="DomainModel.User, DomainModel"
     table="User1Object" entity-name="User1Object">  
         <id name="_id" access="field" column="id">
             <generator class="assigned"/>
         </id>
        <property name= ...>
 </class>
 <class name="DomainModel.User, DomainModel"
     table="User2Object" entity-name="User2Object">
         <id name="_id" access="field" column="id">
            <generator class="assigned"/>
         </id>
        <property name= ...>
</class>
</hibernate-mapping>

Then depending on which type of entity you need you call the appropriate session methods as:

_session.Save("User1Object", user1)

or

_session.Save("User2Object", user2)

Posts 2 & 3 were used as a basis for this snippet. Official source [ 4 ]

After match:

One answer on the first question which is actually link to this post [ 5 ] there is different approach:

You say bye to the first instance of the object, clone the data to fresh instance and persist that with different name. Thus, no violation on Hibernate logic and everybody content: same data at two tables and no sub-classes used.

Well, the implementation or code or credibility of that approach is so and so, I haven't tested it neither.

Another case:

In this post [ 6 ] there is another person trying to challenge the super class approach with something simpler, but again, the most credible answer states it is not possible another way around, the official non-xml approach is the said subclass approach.

Sources

[1] How to map one class to different tables using hibernate/jpa annotations

[2] Map Two Identical tables ( same schema...) to same entity in Hibernate

[3] How to map 2 identical tables (same properties) to 1 entity

[4] http://docs.jboss.org/hibernate/core/3.2/reference/en/html/mapping.html#mapping-entityname

[5] Hibernate 4: One class mapping Two tables - How to persist one object on both tables?

[6] Hibernate Annotation for Entity existing in more than 1 catalog

Also it works using a default entity and an alternative one:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
   <class name="DomainModel.User, DomainModel"
     table="User1Object">  
         <id name="_id" access="field" column="id">
             <generator class="assigned"/>
         </id>
        <property name= ...>
 </class>
 <class name="DomainModel.User, DomainModel"
     table="User2Object" entity-name="User2Object">
         <id name="_id" access="field" column="id">
            <generator class="assigned"/>
         </id>
        <property name= ...>
</class>
</hibernate-mapping>

For the default one, you can use the method

_session.Save(user1)

and

_session.Save("User2Object", user2)

for the alternative one.

You can do it using configuration:

  • Create two mappings for the same Entity Class name , but give them different logical entity-name , and table name.
  • Then use the Session methods where you provide the entityName as a parameter to distinguish one from the other.

What does this achieve?

  • "Virtual subtyping"
  • When retrieving data into the type, you must specify one entity-type or the other (thus implying one table or the other)
  • When you modify data and save it, you must specify the same entity-type - an attempt to update with a different entity-type should be rejected by hibernate. Otherwise, modified entities will already have an identifier populated, so hibernate will try to update rather than insert, but that would fail in the database - attempt to update data that never existed in the table.
  • This leads to segregation - you must commit to one entity-type when working on an entity or a list of entities, and can't mix the two. ie "virtual subtyping"

What are the costs?

  • It gives very weak typing. The compiler and runtime have no indication of the true subtype. Errors are waiting to happen and might be tricky to debug.
  • It's non-standard. JPA has steered clear of this, I believe it's not on the radar for inclusion, and for good reason.
  • You must use XML, not annotations.
  • You must call unusual methods, including the "entity-type" parameter.

Are there benefits over subtyping?

  • None that I can see

Should you do it?

  • I don't think so! Use subtyping and standard code.

Although i have never used but there is a concept of Secondary Table in hibernate. And @SecondaryTables is the annotation in hibernate by which an entity can map more than one table to fetch the data. The entity which is fetching data should have @SecondaryTables annotations. It associates secondary table on the basis of primary and foreign key and also on the basis of unique constrains.

Here is one sample I found after doing google, check whether it helps you to achieve :

http://www.concretepage.com/hibernate/secondarytables_hibernate_annotation.php

I know this question was asked long time ago. But I would like to suggest an alternative way, without using any of hibernate things. For those who don't want to use xml configuration.

Declare an interface with getter and setter methods of commun columns, then make your tow entity classes implement this interface. Leave the mapping annotations in this two entity class as usual, then in your code, you can invoke method of this interface instead.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM