How to do inheritance in Hibernate? - java

I have some 10 tables with the following schema
ID
Year
Code
Section
Period
Date
Status
Each table has a name data_1, data_2 and so on. Now I want to write Hibernate mapping for these tables. As all these tables have the same schema with only the names different I wrote a POJO file with data as super class and all the other 10 classes inheriting it.
What do I do now with the hbm files? Do I have to write one hbm file for each table? I tried the union-subclass, but somehow I couldn't get it right. I am getting a lot of unexplained errors in Hibernate.
How can I write the Hibernate mapping in this type of scenario? I am a starter in Hibernate and please note that the choice of database design is not in my hands. I have 30 such similar type of hierarchies.

First you must understand that there is no such thing as inheritance in relational database system. But there are strategies to map the inheritance structure to the database.
Check out the hibernate documentation at http://docs.jboss.org/hibernate/core/3.3/reference/en/html/inheritance.html
As far as I understand, your strategy is "Table per concrete class"

First of all you need to choose what type of strategy you want for the inheritance. There are a few options.
Have a look at this link here where it describes a little about inheritance in JPA. Hibernate supports JPA, so the mappings should be the same, ie:
Note however that this is the mapping type for EclipseLink
<entity name="Project" class="Project" access="FIELD">
<table name="PROJECT"/>
<inheritance strategy="JOINED"/>
<discriminator-value>P</discriminator-value>
<discriminator-column name="TYPE"/>
<attributes>
<id name="id"><column name="ID"/> </id>
</attributes>
</entity>
<entity name="LargeProject" class="LargeProject" access="FIELD">
<table name="L_PROJECT"/>
<discriminator-value>L</discriminator-value>
</entity>

Related

How to properly outline an Apache Solr document?

What is the difference between delta import and full import in ApacheSolr?
What are all the naming conventions to be followed while writing deltaImportQuery and deltaQuery ( ID, TXT_ID etc), any references or tutorial explaining in detail about differences/relations between deltaImportQuery and deltaQuery, Like what it is and what it does etc, How to write deltaImportQuery and deltaQuery ?
How to configure multiple entities in one document, Suppose if there are three tables in database like T1, T2, T3, Then in schema.xml how to configure this, issue with only one <uniquekey>somename</uniquekey> been considered for each schema.xml file?
How to parse BLOB type input from mysql, following convert ( column_name using utf8 ) as alias_name solves this but what is the right convention ,some other methods are also available like using TikaEntityProcessor/ writing custom BLOBTRANSFORMERS etc ?
Just like ORM any concepts explaining how to denormalize and outline an Apache Solr document , Any showcase project including all use cases and features ?
How to configure entities like this in data-config.xml?
<dataConfig>
<dataSource type="JdbcDataSource" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/solrdemo" user="root" password="123" batchSize='1' />
<document name="user">
<entity name ="user1" query = "SELECT * FROM user1">
<field column='id' name='id1' />
</entity>
<entity name ="user2" query = "SELECT * FROM user2">
<field column='id' name='id2' />
</entity>
<entity name ="user3" query = "SELECT * FROM user3">
<field column='id' name='id3' />
</entity>
</document>
</dataConfig>
When the above kind of configuration is done then in schema.xml which id should be configured into <uniquekey></uniquekey> ?
The result of above configuration is
Indexing completed. Added/Updated: 2,866 documents. Deleted 0 documents. (Duration: 03s)
Indexing is successfully completed but 0 documents added / updated , How to resolve this issue ?
Overall any references available for proper conventions and configurations to work with Apache Solr?

Solr query only returns Id's

I have wanting to import data from a table and index it using solr..
I am using solr-tomcat admin panel.
But whenever I query it returns to me only the id's and value.
I have also tried adding FIELDS to fl , but that also does not help.
here is my data-config.xml file:
<dataConfig>
<dataSource type="JdbcDataSource"
driver="com.mysql.jdbc.Driver"
url="jdbc:mysql://127.0.0.1:3306/{DB_NAME}"
user="{DB_USER}"
password="{DB_PASSS}"
/>
<document>
<entity name="id" query="select s3_location,file_name from video">
<field column="s3_location" name="s3_location"/>
<field column="file_name" name="file_name"/>
</entity>
</document>
</dataConfig>
Is there any way to get the above s3_location and file_name fields also.
You need to specify the actual field names in the fl parameter or use * to indicate all fields. Also, please note that the fields must have been defined with stored=true in your schema.xml file for them to be returned/visible during a query.
fl=id,s3_location,file_name
fl=*
Are you sure you are importing the data at all? If you start with empty index, do you get anything?
The reason I ask is because you are not mapping the id field explicitly. Now, I believe there is implicit mapping of the fields by Jdbc data source based on names, but relying on it is risky when you are just starting.
Otherwise, like Paige said, make sure you defined those fields in your schema and that they are actually stored.

how can i use subclasses in hibernate for attributes within a table?

I have the following domain objects
Loan {
int id;
Date attribute1;
}
LoanExtension {
Date attribute2;
}
I would like to keep my objects like this because sometimes I would like to change only the attributes in LoanExtension in my database (i.e. attribute1 in the loan object will be null in the object and i don't want this to get set in the database).
How is this possible using a hibernate mapping with xml? I have done the following
<class name="org.domain.borrowerReview.Loan" table="loan_profiles" >
<cache usage="read-only"/>
<id name="loanId" column="id">
<generator class="native"/>
</id>
<version name="attribute1" column="date_1/>
<subclass name="org.domain.borrowerReview.LoanExtension" extends="org.rangde.domain.borrowerReview.LoanProfilesUpdate">
<property name="attribute2" column="date_2" />
</subclass>
</class>
I'm getting this exception :
Discriminator is needed when 'single-table-per-hierarchy' is used and a class has subclasses
Short answer
You need to add a discriminator column and change the snippet to something like this.
<class name="org.domain.borrowerReview.Loan" table="loan_profiles" >
<cache usage="read-only"/>
<id name="loanId" column="id">
<generator class="native"/>
</id>
<version name="attribute1" column="date_1/>
<discriminator column="loan_profiles_type" type="string"/>
<subclass name="org.domain.borrowerReview.LoanExtension" extends="org.rangde.domain.borrowerReview.LoanProfilesUpdate">
<property name="attribute2" column="date_2" />
</subclass>
</class>
Long answer
First off, do remember that the inheritance in JPA is not an absolute parallel to regular inheritance.
One must evaluate how the design of classes will have an impact on the underlying schema.
You have not mentioned how you would like to have your table structure as.
Hibernate provides three mechanisms for inheritance.
table per class hierarchy
table per subclass
table per concrete class
See detaiils here
Your xml snippet suggests that you are using table per class hierarchy.
Now, if one has subclasses, there would be little use if the is just one subclass (though it is allowed). And under "table per class hierarchy" all the sub classes are placed in the same table.
To distinguish between which subclass a particular record belongs to, hibernate relies on discriminator column.
You need to define the same.
Refer the following documentation documentation.

Apache Cayenne many-to-many relationship

I'm new with Apache Cayenne.
I have only one Entity, called Product.
This entity has a many-to-many relationship with itself, that is a product can contain products, and it can be contained by other products.
I can't model this relationship with Cayenne..
What I do is:
1) I create a table called Composition, with two fields that are both PKs and FKs.
2) I create two toMany from Product to Composition (one from product.id to Composition.contained_id, and one from product.id to Composition.base_id)
This should work with the DB
Now I create only one ObjEntity: Product.
But.. How can I create a flattened relationship?? I'm following this: http://cayenne.apache.org/doc/cayennemodeler-flattened-relationships.html but maybe because it is a relationship with itself I cannot select an Entity in "Target" combo box..
Thank you
Francesco
EDIT: the target checkbox problem there is also if the two entities are different. Cayenne Modeler v.3.0.2
"Target" combo is empty when you select the first relationship, simply because there's no ObjEntity for the join table. But if you keep selecting the next path component, "Product" will appear in the combobox. I wish we redesign this UI for better clarity, but it still works now. See the DataMap XML sample below. I just created it with 3.0.2 Modeler.
Hope this helps.
<?xml version="1.0" encoding="utf-8"?>
<data-map xmlns="http://cayenne.apache.org/schema/3.0/modelMap"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://cayenne.apache.org/schema/3.0/modelMap http://cayenne.apache.org/schema/3.0/modelMap.xsd"
project-version="3.0.0.1">
<db-entity name="composition">
<db-attribute name="BASE_ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
<db-attribute name="CONTAINED_ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
</db-entity>
<db-entity name="product">
<db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
<db-attribute name="NAME" type="VARCHAR" length="255"/>
</db-entity>
<obj-entity name="Product" dbEntityName="product">
<obj-attribute name="name" type="java.lang.String" db-attribute-path="NAME"/>
</obj-entity>
<db-relationship name="base" source="composition" target="product" toMany="false">
<db-attribute-pair source="BASE_ID" target="ID"/>
</db-relationship>
<db-relationship name="contained" source="composition" target="product" toMany="false">
<db-attribute-pair source="CONTAINED_ID" target="ID"/>
</db-relationship>
<db-relationship name="base" source="product" target="composition" toDependentPK="true" toMany="true">
<db-attribute-pair source="ID" target="BASE_ID"/>
</db-relationship>
<db-relationship name="contained" source="product" target="composition" toDependentPK="true" toMany="true">
<db-attribute-pair source="ID" target="CONTAINED_ID"/>
</db-relationship>
<obj-relationship name="base" source="Product" target="Product" deleteRule="Deny" db-relationship-path="contained.base"/>
<obj-relationship name="contained" source="Product" target="Product" deleteRule="Deny" db-relationship-path="base.contained"/>
</data-map>

Hibernate one-to-many + lazy loading

I have an Account entity and an AccountTransaction entity.
Account 1 <----> n AccountTransaction
In my AccountTransaction.hbm.xml I specify a many-to-one relationship:
<hibernate-mapping>
<class name="com.walshk.accountmanager.domain.AccountTransaction" table="AccountTransaction">
<id name="id" type="long" column="transaction_id">
<generator class="increment"/>
</id>
<property name="date" not-null="true" type="date" column="transaction_date"/>
<property name="description" not-null="true" column="transaction_description" length="500"/>
<property name="amount" column="transaction_amount" not-null="true"/>
<many-to-one name="account" column="account_id" not-null="true" cascade="all" lazy="false"/>
</class>
</hibernate-mapping>
This allows me to lookup AccountTransactions by account using
Criteria criteria = session.createCriteria(AccountTransaction.class)
.add(Restrictions.eq("account", account));
and also allows me to get the Account instance using AccountTransaction#getAccount();
What I want to do now is provide a way to get an account, e.g
Criteria criteria = session.createCriteria(Account.class).add(Restrictions.eq("id", id));
But I also want the Account entity to have a method
List<AccountTransaction> getTransactions();
And I want this to be lazy loaded, since I may not even need to list the transactions.
Since I am already specifying the relationship as many-to-one from the AccountTransaction how do I now specify a one-to-many relationship giving me access from the other direction.
Additionally, what's the best way to handle lazy-loading, do I have to assign a session to each entity and not close the session? I could potentially have too many sessions open though.
Thanks.
If you add a One-to-Many association in your Account class hibernate mapping, you will get:
List<AccountTransaction> getTransactions();
from any ORM creation tool.
One of the parameters of this association is the loading type - I am not familiar with the exact syntax in XML mapping, as we use annotations, but you could probably find it in any reference/documentation page of hibernate XML mapping.
in Order to work with Lazy Loading, You should have Open Session in view enabled.
If you are using Spring integration that you have OpenSesionInViewIntereptor/OpenSessionInViewFilter
If you are using native Hibernate without Spring integration, then you can implement it by yourself.
Please read the following:
http://community.jboss.org/wiki/OpenSessioninView
Hope it helps.

Categories