views:

83

answers:

5

For a project I am working on, I need to persist a number of POJOs to a database. The POJOs class definitions are sometimes highly nested, but they should flatten okay, as the nesting is tree-like and contains no cycles (and the base elements are eventually primitives/Strings). It is preferred that the solution used create one table per data type and that the tables will have one field per primitive member in the POJO. Subclassing and similar problems are not issues for this particular project.

Does anybody know of any existing solutions that can:

  1. Automatically generate a CREATE TABLE definition from the class definition
  2. Automatically generate a query to persist an object to the database, given an instance of the object
  3. Automatically generate a query to retrieve an object from the database and return it as a POJO, given a key.

Solutions that can do this with minimum modifications/annotions to the class files and minimum external configuration are preferred.


Example:

Java classes

//Class to be persisted
class TypeA {
  String guid;
  long timestamp;
  TypeB data1;
  TypeC data2;
}

class TypeB {
  int id;
  int someData;
}

class TypeC {
  int id;
  int otherData;
}

Could map to

CREATE TABLE TypeA (
  guid CHAR(255),
  timestamp BIGINT,
  data1_id INT,
  data1_someData INT,
  data2_id INt,
  data2_otherData INT
);

Or something similar.

A: 

You tagged your question as Hibernate. Have you tried using Hibernate for this?

As long as you define well how collections should be mapped (e.g., one-to-many), I've found it generally very effective for this kind of thing.

The Hibernate tutorials provide a lot of examples for situations that are similar to the code you provided.

Uri
I did look into Hibernate, but couldn't find any functionality that allowed me to automatically generate the SQL descriptions given already-existing class descriptions. Do you know of any part of Hibernate that can be used for this (or that could serve as the basis for some Googling)?
VeeArr
Do you need the actual SQL for logging purposes? I mean, Hibernate will do SQL for all of this including creating your tables in your database of choice. There's a logging option that lets it also dump the SQL. If you actually want to manipulate the SQL in your program (why?), that might be doable, but I'm not sure how.
Uri
I was unclear, sorry. What I meant was that I did not want to have to go and create the tables manually by myself, nor did I want to have to do a field-by-field mapping of the Java objects to the fields in the database. I do not have any need for the actual SQL used (apart from possibly logging purposes, as you said).
VeeArr
Hibernate includes a tool called hbm2dll, which will generate your database schema for you.
JacobM
+1  A: 

Hibernate can help you solve all the three problems you listed.

(1) You need to annotate your entity classes so Hibernate is able to map between classes/objects to tables/rows. Hibernate uses a convention over configuration approach so it is possible to use just a few annotations and have a complete o/r mapping ready for use. You could use the hibernate.hbm2ddl.auto configuration option to instruct Hibernate to automatically validate/export and schema DDL when the session factory is first created.

(2) / (3) Hibernate has enough information about classes, database schema and mappings to allow it generate SQL statements for simple CRUD operations with minimal effort. You can fine tune how Hibernate loads and persists a tree of objects. Association mapping annotations have the fetch and cascade options that let you specify how associated objects are fetched (lazy / eager) and how operations are propagated through the object tree. Please refer to the Hibernate documentations for the details about these options.

If you are new to Hibernate, I recommend the good Hibernate documentation as reference and the book Java Persistence with Hibernate for the deeper understanding about the framework (it has very good sections about fetching and cascading).

In a typical scenario, Hibernate requires just a bit of configuration (one hibernate.cfg.xml file). You can define the mappings using XML files (no good) or annotations (the "default" option for new projects).

matheus.emm
+1  A: 

A highly recommended framework is JPersist, an extremely simple Database-to-POJO framework. No XML or annotations needed. I use it it my project because if I want a new table object, I simply create a bean.

The issue though in your situation is your wanting something to setup the database for you. Doing that would be very hard and your asking alot from a framework. With JPersist, you should be able to create a db table from class name and columns from fields, and then use phpMyAdmin's designer to resolve references.

5 min of reading the documentation for JPersist now will save hours in development time later.

TheLQ
JPersist looks very tempting, due to the lack of need for annotation or mapping. However, from the few minutes I spent looking at the documentation, it seemed that I would need to manually set up the database tables ahead of time. Unfortunately, since the datatypes could have upwards of 100 fields each, and there are nearly 100 data types, I would prefer not to do this.
VeeArr
+2  A: 

I would use the standardized Java Persistence API (JPA), preferably with annotations. Regarding your requirements:

  1. This is not required by the specification but most JPA providers (all major implementations do) support DDL generation from the mapping metadata.
  2. EntityManager#persist(Object entity) does that.
  3. <T> T EntityManager#find(Class<T> entityClass, Object primaryKey) does that.

As hinted, JPA is an API, you need an implementation to use it. My preference goes to Hibernate Entity Manager or EclipseLink (see this previous question).

Pascal Thivent
+1 for been the only person to recommend JPA. Perhaps link to the EE 6 [JPA tutorial](http://java.sun.com/javaee/6/docs/tutorial/doc/bnbpz.html).
Justin
@Justin Much better link indeed. Answer updated with it. Thanks.
Pascal Thivent
A: 

JPA provides sufficient options to do this. For example you can use @Embeddable and @Embedded:

@Embeddable
class TypeB {
  int id;
  int someData;
}


class TypeA {
  ....
  @Embedded
  TypeB data1;
}

You can either manually create the underlying schema, or let something like hbm2ddl.auto=update to create it for you.

Bozho