Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate entities without underlying tables

I have a really ugly legacy database system that I need to integrate with. Essentially I'm doing some read only reporting on the system, and I don't want to set up a thousand entities representing each of the tables that I'm working on. Instead, I'd like to just define an Entity for each of the report-types that I generate (essentially a union of a bunch of columns from different tables), and then let hibernate map from the nasty (many joined, many unioned) sql query to a list of such entities.

The question is: can I create an entity that doesn't have an underlying table, and use a sql statement to populate a list of said entities?

Thanks!

like image 616
idbentley Avatar asked Nov 03 '11 23:11

idbentley


People also ask

Can we create entity in Hibernate without primary key?

Not with Hibernate. It requires a primary key.

Can an entity class work without having a definition for all columns of the table?

Of-course if you use it only for querying purpose then it should be fine.

Can we have an entity without @ID JPA?

More precisely, a JPA entity must have some Id defined. But a JPA Id does not necessarily have to be mapped on the table primary key (and JPA can somehow deal with a table without a primary key or unique constraint).

What is the difference between @entity and @table in Hibernate?

Entity means the class which you will use in your program and Table means the actual Database table that you will access through your program. Hibernate being an ORM requires you to declare the relationship between the tables and the classes mapping to them.


3 Answers

We do that sort of thing all the time - and here is how we do it:

  1. Define a simple bean-like object to represent each row of output in your report:

    public class CityStateRevenueReport {
    
        private String mId;
        private String mState;
        private String mCity;
        private Double mRevenue;
    
        public String getId() { return mId; }
        public void setId(String i) { mId = i; }
        public String getState() { return mState; }
        public void setState(String s) { mState = s; }
        public String getCity() { return mCity; }
        public void setCity(String c) { mCity = c; }
        public Double getReveneue() { return mRevenue; }
        public void setRevneue(Double d) { mRevenue = d; }
    }
    
  2. Define a hibernate mapping file, CityStateRevneueReport.hbm.xml:

    <?xml version="1.0" ?>
    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd&quot;>
    <hibernate-mapping>
        <class entity-name="CityStateRevenueReport">
            <id name="Id" type="java.lang.String" column="report_id">
                <generator class="sequence" />
            </id>
            <property name="city" type="string" column="city" />
            <property name="state" type="string" column="state" />
            <property name="revenue" type="double" column="revenue" />
        </class>
        <sql-query name="runReport">
            <![CDATA[ 
            SELECT {r.*} FROM 
                (select some_id_value as report_id, 
                        state_abbreviation as state, 
                        city_name as city, 
                        dollar_amount as revenue 
                   from -- tables, joins, other SQL insanity 
                 ) r
            ]]>
            <return alias="r" class="CityStateRevenueReport" />
        </sql-query>
    </hibernate-mapping>
    
  3. Then run the query and populate instances:

    public List<CityStateRevenueReport> runReport() {
    
        List<CityStateRevenueReport> reports = 
                                 new ArrayList<CityStateRevenueReport>();
        List<HashMap> maps = session.getNamedQuery("runReport").list()
        for ( HashMap map : results ) {
            CityStateRevenueReport report = new CityStateRevenueReport();
            report.setState(map.get("state"));
            report.setCity(map.get("city"));
            report.setRevenue(Double.parseDouble(map.get("revenue"));
            reports.add(report);
        }
        return reports;
    }
    
like image 54
Jason Buberel Avatar answered Oct 21 '22 06:10

Jason Buberel


Use an Entity query:

http://docs.jboss.org/hibernate/core/3.3/reference/en/html/querysql.html#d0e13696

sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").addEntity(Cat.class);

Or create a view in the database and map against that.

Here's a longer tutorial using addEntity:

http://timezra.blogspot.com/2009/05/mapping-hibernate-entities-to-views.html

private Collection<AuthorAggregate> findByFirstName() {
    return sessionFactory.getCurrentSession() //
            .createSQLQuery(AUTHORS_BY_FIRST_NAME) // 
            .addEntity(AuthorAggregate.class) //
            .list();
}
like image 41
Scott A Avatar answered Oct 21 '22 06:10

Scott A


If you're free to choose hibernate or not, I suggest you take a look at Spring JDBC. it's lighter than hibernate and does the job right. With your requirements it will suit nicely into the picture.

like image 28
WeMakeSoftware Avatar answered Oct 21 '22 05:10

WeMakeSoftware