JPA - Change table at runtime - java

Tables
sales_2009
sales_2008
sales_2007
And only one class (sales), How change the table at runtime?

How change the table at runtime?
That's not supported out-of-the-box by standard JPA. But implementation might provide extensions for Horizontal partitioning:
Hibernate has Shards.
EclipseLink has a SessionBroker feature.
OpenJPA has a Slice plug-in.
I can't say anything about the maturity of Slice.
An alternative solution would be to define three different persistence units and to map the Sales entity specifically in each of them (possibly using XML mappings to reuse the Java code). And then, obtain the "right" EntityManager from the appropriate EntityManagerFactory. This solution is not ideal from a memory point of view though (plus some other limitations).
See also
News: Slice: OpenJPA for distributed persistence
Slice: OpenJPA for distributed persistence

Thanks for the reply, I solved with iBATIS
In the file map (xml)
select * from $table$ where date = #date# and product_id = #product_id#
*In the file Java - example with Servlet:-
Map parameter = new HashMap();
parameter.put("table", "sales2009");
parameter.put("date", "2009-10-08"); //MySQL date :)
parameter.put("product_id",17);
SqlMapClient sqlMap = (SqlMapClient) getServletContext().getAttribute("sqlMap");
List result = sqlMap.queryForList("selectSalesByParameters",parameter);
for(Sales s : result) { }
Important: $table$ != #table is not working.

Related

How to dynamically add Entity in Hibernate?

I'm a java developer. I'm using spring 4.0.1 and hibernate 4.2.21. I have a class as follow:
#Entity
#Inheritance(...)
public abstract class Feature{
#Id
#GeneratedValue
protected Long id;
...
}
Now I have some many class as follow:
Label.java class:
#Entity
public class Label extends Feature{
protected String str;
...
}
Point.java class:
#Entity
public class Point extends Feature{
protected Integer intg;
...
}
I have more than 20 Entity class that extends from Feature class. Is there any way to add dynamically this classes(such as Label and Point) to the project without writing hard code?
update:
For example, Hibernate get data from a database and then according this data, create models.
Is it possible?
How do I do?
I think its not a good database design that needs to be changed dynamically. It sounds verbose and not consistent. Observe your domain again and try to design a proper entity relationships that wouldnt be changed over run time.
You can try to collect the needed data to build the model and generate a hibernate hbm.xml file for each entity (is xml format and easy to generate with java after reading the data needed as you describe in your update)
After that, you can create programmatically a hibernate configuration object following this http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/session-configuration.html#configuration-programmatic
I Think with that approach you can achieve what you want if I understand well your question.
I think you want to generate your entity class at runtime instead of that you have to write your java file and compile it and so on.
If this is your requirement you can use a byte code generator like javassist to generate and annotate your class file at runtime. Then you can persist it to your table using JPA, Hibernate and any other ORM framework.
As I understand you need to develop a tool, collects table names that have one-to-one relationship with Feature table.
My suggestion is like that (tested with Oracle):
1) From your DB, get tables metadata who is referancing your Feature table.
Below will print your Label, Point, etc tables who has foreign key relation to your table.If you want to only generate a subset (irrelevant tables might has this relationship too) may be you put a common foreign key column name and filter out non-related tables with a help of such marking.
Connection connection = jdbcTemplate.getDataSource().getConnection();
DatabaseMetaData metaData = connection.getMetaData();
ResultSet exportedKeys = metaData.getExportedKeys(connection.getCatalog(), "<your_schema_name>", "FEATURE");
while (exportedKeys.next()){
String fkTableName = exportedKeys.getString("FKTABLE_NAME");
String fkColumnName = exportedKeys.getString("FKCOLUMN_NAME");
System.out.println("[fkTableName:" + fkTableName + "], [fkColumnName" + fkColumnName + "]");
}
exportedKeys.close();
2) For the tables you collected above, for each table of our concern, get table metadata for the types and columns.
ResultSet columns = metaData.getColumns(connection.getCatalog(), "<your_schema_name>", "<your_table_name>", null);
while (columns.next()){
String columnName = columns.getString("COLUMN_NAME");
String typeName = columns.getString("TYPE_NAME");
System.out.println("[columnName:" + columnName + "], [typeName" + typeName + "]");
}
columns.close();
3) According to result from 2 generate your Java classes. With fields, getter setters, annotations etc. Then copy them into your source directory. You know the rest :)
Hope this is helpful.
I think you can use Hibernate Reverse Engineering to generate Entity for all the database tables. Please refer this Link. That will explained step by step process to generate entity from database using hibernate reverse engineering.
Do not repeat yourself.
If you really need those classes use an IDE (like eclipse) to generate the classes. Or use generics and inheritance to create only one class that is capable of storing Strings as well as Integers.
But if you do not actually need classes, generate SQL (not JPQL nor HQL) and to store the data in java.util.Map and similar data structures.
Classes are good for:
type safety
combining logic (methods) with data (fields)
describing relationships
In your case you might only need:
store structured data at runtime.
I think you could do this with eclipse, but the classes had to be modified more or less to preserve the inheritance hierarchy.
Righ click on the project name and select Properties
Use project facets if project facets not enabled
Click the JPA if it's not selected, then click OK to close the project properties window.
After enabling JPA in project properties, now right click you eclipse project name again, you should see a new context menu item JPA tools appears. Choose Generate Entities from tables
Select a database connection to let Eclipse get the tables used to generated
class from.
Here is how to setup db in eclipse
It's better to create the entities in a dummy project using the above method and copy the Entity classes to the real project.
Eclipse's Class refactoring may be used to preserve the inheritance hierarchy that you want.
Hope this helps.

How to get the name of the property that is bound to a column in HBM?

I have created a HBM file. In code I have an actual column name available for me(through a property file). I want to get associated property name of that column to form a HQL. Is there an API that is provided by Hibernate to get the property name that is mapped/bound to a DB column in HBM file?
There is a semi official API for accessing the metadata of classes:
Class<?> entityClass = ...;
String columnName = ...;
EntityManager em = ...;
final SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor)
((Session) em.getDelegate()).getSessionFactory();
AbstractEntityPersister persister = (AbstractEntityPersister) sessionFactory.getClassMetadata(entityClass);
for (String propertyName : persister.getPropertyNames()) {
for (String propertyColumnName : persister.getPropertyColumnNames(propertyName)) {
if (columnName.equalsIgnoreCase(propertyColumnName)) {
return propertyName;
}
}
}
The only thing I could find is this quote from the version 3.5 documentation stating, that at least in JPA ther ist currently no such API. But I couldn't find anything newer, so it seems there still isn't such an API.
As of today the JPA 2 metamodel does not provide any facility for
accessing relational information pertaining to the physical model. It
is expected this will be addressed in a future release of the
specification.
Of course Hibernate must have this information somewhere, at least in the opposite direction, but I don't think they exposing it through an API, which is intended for public use.
You could probably do some hacking by debugging through the hibernate code to see, where they get the information from, when constructing sql statements.

Hibernate reveng persistence model does not validate

I use Hibernate Reverse Engineering to automatically create classes from a database scheme. DB server is MSSQL 2008. This database is designed by a partner and could potentially change without notice. Thus I'd like to have Hibernate validate the scheme on startup, wich in my opinion should work out of the box. But it doesn't:
org.hibernate.HibernateException: Wrong column type in somedb.dbo.ASVC_S for column SomeCol. Found: decimal, expected: numeric(18,0)
The generated enttity class looks like this:
#Column(name="SomeCol", precision=18)
public BigDecimal getSomeCol() {
return this.someCol;
}
Is my assumption that reveng creates classes that can be validated against the schema wrong? Should I skip validation and hope that during runtime everything's OK? Annotating the classes after generating them or maintaining an entry for each class in my reveng.xml mapping file is not an option - too many classes ;)
hibernate-tools is version 4.0.0-CR1.

Why does Hibernate re-implement functionality that databases already have?

For example:
#Table(name = "stock", catalog = "mkyong", uniqueConstraints = {
#UniqueConstraint(columnNames = "STOCK_NAME"),
#UniqueConstraint(columnNames = "STOCK_CODE") })
or
#Column(name = "STOCK_NAME", unique = true, nullable = false, length = 20)
Constraints like 'unique', 'nullable', even field length are core database features. Why include this here? Also (although this may hurt some) I'd also wager that a database's implementation of such constraints, particularly mainstream commercial DBs like Oracle, is probably better than whatever the OSS Hibernate devs can come up with.
Is it wise to use this type of stuff in Hibernate, or is it a better practice to put constraints and such in the database? It seems that if you utilize these Hibernate features, you're practically treating the database as a file system, so what's the point? Usage of this is everywhere but I've yet to find the documentation explaining why you'd do this.
It does not implement them - it has the option to validate the data model against the schema, or create it.
The hibernate.hbm2ddl.auto configuration property is the one that allows you to create the schema based on the mappings.
Automatically validates or exports schema DDL to the database when the SessionFactory is created. With create-drop, the database schema will be dropped when the SessionFactory is closed explicitly.
e.g. validate | update | create | create-drop
This is very useful, if you want your data model to be in the central place, rather than the database structure
Hibernate can create a database schema based on those annotations for you.

JPA - Setting entity class property from calculated column?

I'm just getting to grips with JPA in a simple Java web app running on Glassfish 3 (Persistence provider is EclipseLink). So far, I'm really liking it (bugs in netbeans/glassfish interaction aside) but there's a thing that I want to be able to do that I'm not sure how to do.
I've got an entity class (Article) that's mapped to a database table (article). I'm trying to do a query on the database that returns a calculated column, but I can't figure out how to set up a property of the Article class so that the property gets filled by the column value when I call the query.
If I do a regular "select id,title,body from article" query, I get a list of Article objects fine, with the id, title and body properties filled. This works fine.
However, if I do the below:
Query q = em.createNativeQuery("select id,title,shorttitle,datestamp,body,true as published, ts_headline(body,q,'ShortWord=0') as headline, type from articles,to_tsquery('english',?) as q where idxfti ## q order by ts_rank(idxfti,q) desc",Article.class);
(this is a fulltext search using tsearch2 on Postgres - it's a db-specific function, so I'm using a NativeQuery)
You can see I'm fetching a calculated column, called headline. How do I add a headline property to my Article class so that it gets populated by this query?
So far, I've tried setting it to be #Transient, but that just ends up with it being null all the time.
There are probably no good ways to do it, only manually:
Object[] r = (Object[]) em.createNativeQuery(
"select id,title,shorttitle,datestamp,body,true as published, ts_headline(body,q,'ShortWord=0') as headline, type from articles,to_tsquery('english',?) as q where idxfti ## q order by ts_rank(idxfti,q) desc","ArticleWithHeadline")
.setParameter(...).getSingleResult();
Article a = (Article) r[0];
a.setHeadline((String) r[1]);
-
#Entity
#SqlResultSetMapping(
name = "ArticleWithHeadline",
entities = #EntityResult(entityClass = Article.class),
columns = #ColumnResult(name = "HEADLINE"))
public class Article {
#Transient
private String headline;
...
}
AFAIK, JPA doesn't offer standardized support for calculated attributes. With Hibernate, one would use a Formula but EclipseLink doesn't have a direct equivalent. James Sutherland made some suggestions in Re: Virtual columns (#Formula of Hibernate) though:
There is no direct equivalent (please
log an enhancement), but depending on
what you want to do, there are ways to
accomplish the same thing.
EclipseLink defines a
TransformationMapping which can map a
computed value from multiple field
values, or access the database.
You can override the SQL for any CRUD
operation for a class using its
descriptor's DescriptorQueryManager.
You could define a VIEW on your
database that performs the function
and map your Entity to the view
instead of the table.
You can also perform minor
translations using Converters or
property get/set methods.
Also have a look at the enhancement request that has a solution using a DescriptorEventListener in the comments.
All this is non standard JPA of course.

Categories

Resources