问题
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!
回答1:
We do that sort of thing all the time - and here is how we do it:
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; } }
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"> <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>
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; }
回答2:
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();
}
回答3:
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.
来源:https://stackoverflow.com/questions/8002989/hibernate-entities-without-underlying-tables