Automatically Persisting a Complex Java Object - java

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:
Automatically generate a CREATE TABLE definition from the class definition
Automatically generate a query to persist an object to the database, given an instance of the object
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.

I would use the standardized Java Persistence API (JPA), preferably with annotations. Regarding your requirements:
This is not required by the specification but most JPA providers (all major implementations do) support DDL generation from the mapping metadata.
EntityManager#persist(Object entity) does that.
<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).

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).

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.

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.

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.

Related

Use Transient property in Hibernate

First off, I'm new to Hibernate.
I have a standalone Java application built in Netbeans, trying to keep to the MVC model as much as possible. My model classes resemble the database tables and columns as much as possible. The database is normalized to avoid redundancy.
However, I noticed that it was convenient to have a certain property available in many of my model classes. This property is available in the database, but in most situations it is necessary to do multiple joins to get it.
Therefore, I added this property to my model classes for easier access.
Example:
Object A has a relation with Object B, which has a relation with Object C. Object C has the property X.
The relations are one-to-many; Object A has the primary key of Object B as a column, and so forth.
Now I want to find all Object A connected to property X. I have to do multiple joins to get the answer. Property X also applies to Object A, but I don't want it as a property for Object A in the database, as that is redundancy. In the application, I add this property X to the class of Object Afor convenient access.
Now I want to implement Hibernate instead of my own designed (service) classes, and I'm not sure what to do with this property. I have defined it as 'Transient' in the POJO, but how do I fill this property? If I let Hibernate perform a get tot the database and return the object (Object A) to me, it will not have this property. Do I need to have an extra constructor with this property and transform Hibernate's object to the one containing this property and return that to the original method that asked for it?
What is the correct way to do this?
If you are using Hibernate you probably have something like this in your class A:
#OneToMany
private Collection<B> listOfB;
In B you will have:
#OneToMany
private Collection<C> listOfC;
So when you get the A Entity from your Database you can get x doing:
a.getlistOfB(0).getListOfC(0).getX();

How does Hibernate work with normalized databases?

Preliminary Info
I'm currently trying to integrate Hibernate with my team at work. We primarily do Java web development, creating webapps that provide data to clients. Our old approach involves calling stored procedures with JDBC (on top of Oracle boxes) and storing their results in beans. However, I've heard a lot about the benefits of integrating Hibernate into a development environment like ours so I'm attempting to move away from our old habits. Note: I'm using the Hibernate JPA annotation approach due to simplicity for team adoption's sake.
Specific Problem
The specific issue I'm having currently is using Hibernate with normalized tables. We have a lot of schemas structured like so:
StateCodes (integer state_code, varchar state_name)
Businesses (integer business_id, varchar business_name, integer state_code)
I want to be able to have a single #Entity that has all of the "Businesses" fields, except instead of "state_code" it has "state_name". To my understanding, Hibernate treats #Entity classes as tables. The #OneToMany, #OneToOne, #ManyToOne annotations create relationships between entities, but this is a very simplistic, dictionary-like lookup and I feel like it doesn't apply here (or might be overkill).
One approach I've seen is
#Formula("(select state_name from StateCodes where Businesses.state_code = state_code)")
private String stateCode;
But, given Hibernate's perk of "avoiding writing raw SQL", this seems like bad practice. Not to mention, I'm extremely confused about how Hibernate will then treat this field. Does it get saved on a save operation? It's just defined as a query, not a column, after all.
So what is the best way to accomplish this?
I do not see any reason not use the standard JPA mappings in this case. Short of creating a database view and mapping an entity to that (or using the non-JPA compliant #Formula) then you will have to map as below.
Unless you are providing a means for the State to be changed then you do not need to expose the State entity to the outside world: JPA providers do not need getters/setters to be present.. Neither do you need to Map a State to Businesses:
#Entity
#Table(name = "Businesses")
public class Business{
//define id and other fields
#ManyToOne
#JoinColumn(name = "state_code")
private State state;
public String getStateName(){
return state.getName();
}
}
#Entity
#Table(name="StateCodes")
public class State{
//define id and other fields.
#Column(name = "state_name")
private String stateName;
public String getStateName(){
return stateName;
}
}

DynamicRelationshipType in Spring Data Neo4j or defining relationship types at runtime

Can I specify relationship type at runtime??
I am creating a set of relationshipEntity objects within an Entity using something like
#Fetch
#RelatedToVia(type="RELATED_IN_SOME_WAY", direction = Direction.BOTH)
Set<ThingRelationship> relationships = new HashSet<ThingRelationship>();
where ThingRelationship is
#RelationshipEntity
public class ThingRelationship {
public ThingRelationship() {
super();
}
//incremental neo4j set ID
#GraphId Long nodeId;
//Start and end nodes
#StartNode Thing startThing;
#EndNode Thing endThing;
//Relationship Type
#org.springframework.data.neo4j.annotation.RelationshipType
String relationship;
However I DONT want to specify the relationship type (type="RELATED_IN_SOME_WAY") at compile time but rather at runtime. When I remove type="RELATED_IN_SOME_WAY I get an error that a default type must be defined
In Neo4j such a runtime relationship type I think requires the use of DynamicRelationshipType however I dont think the Spring Data Neo4j supports this concept.
Am I correct and if so is there anyway around this problem? Do I need to dump Spring Data Neo4j and go to use the Core API instead?
In Neo4j such a runtime relationship type I think requires the use of DynamicRelationshipType however I dont think the Spring Data Neo4j supports this concept.
From the reference documentation
Note
Because dynamic type information is, well, dynamic, it is generally
not possible to read the mapping backwards using SDN. The relationship
still exists, but SDN cannot help you access it because it does not
know what type you gave it. Also, for this reason, we require you to
specify a default relationship type, so that we can at least attempt
the reverse mapping.
So while the dynamic relationship is still created, it can't use that information to retrieve the nodes/relationships back from the Neo4j db. The default relationship is required so that SDN can at least return the known relationship.
Am I correct and if so is there anyway around this problem? Do I need to dump Spring Data Neo4j and go to use the Core API instead?
You can use the SDN to create all dynamic relationships you want using the #RelationshipType but you can't retrieve it back using the default API. You can use write your own Cypher or write traversal code and attach it to your repository or a node property using #Query.

JPA inheritance alternative for SINGLE_TABLE?

AppEngine only supports "TABLE_PER_CLASS" and "MAPPED_SUPERCLASS" for JPA inheritance.
Unfortunately "JOINED" and especially "SINGLE_TABLE" are not supported.
I'm wondering what the best alternative is to implement a SINGLE_TABLE alternative?
My only requirements are:
1) Have separate classes like AbstractEmployee, InternalEmployee, ExternalExmployee.
2) Being able to run a query over all employees, thus resulting in both InternalEmployee and ExternalEmployee instances.
The only thing I'm thinking off is using a 'big' Employee object containing all fields?
Any other ideas?
PS: vote for proper "SINGLE_TABLE" support via http://code.google.com/p/googleappengine/issues/detail?id=8366
You could in theory use #Embeded and #Embeddable to group related fields into an object. So you would have a class that looks something like.
#Entity
public class Employee {
// all the common employee fields go here
//
// the discriminator column on Employee class lets you be specific in your queries
private Integer type;
#Emebded
private Internal internal; // has the fields that are internal
#Embeded
private External external; // has the fields that are external
equals & hashcode that compare based on the discriminator type and other fields
}
What AppEngine supports and doesn't support is misleading there. AppEngine uses a property store, so any Kind can have any properties. Consequently, in principle, a Kind can contain InternalEmployee and ExternalEmployee "instances". The only thing that AppEngine JPA actually does is store all fields of a class in a single Kind object. That doesn't preclude having subtypes stored in the same Kind (with extra properties for the subtype-specific fields), which is the equivalent of "single-table".
PS, raising some issue on "AppEngine" as a whole won't get any response (look at the rest of issues in there ;-) ), bearing in mind the code affected here is in its own project at http://code.google.com/p/datanucleus-appengine and has its own issue tracker

Storing historical data with Java and Hibernate

This is a problem about historical data handling.
Suppose you have a class MyClass like the following one:
class MyClass {
String field1;
Integer field2;
Long field3;
getField1() {...}
setField1(String ...) {...}
...
}
Now, suppose I need to make MyClass able to store and retrieve old data, what's the best way to do this?
The requirements are to persist the classes through Hibernate, too. And to have at most two tables per "entity": only one table or one table for the "continuity" class (the one which represents the entity which evolves over the time) and another table for the historical data (as it's suggested here)
Please note that I have to be able to assign an arbitrary valid time to the values of the fields.
The class should have an interface like:
class MyClass {
// how to store the fields????
getField1At(Instant i) {...}
setField1At(Instant i, String ...) {...}
...
}
I'm currently using the JTemporal library, and it has a TemporalAttribute<T> class, which is like a map: you can do things like T myAttr.get(Instant i) to get the version of myAttr at Instant i. I know how to persist a TemporalAttribute in a table with Hibernate (it's simple: I persist the SortedMap used by the TemporalAttribute and you get a table with start and end valid time and the value of the attribute).
The real problem is that here we have multiple attributes.
I have a solution in mind but it's not clear, and I'd like to hear your ideas.
Your project reminds me of Hibernate Envers.
The Envers project aims to enable easy
auditing of persistent classes. All
that you have to do is annotate your
persistent class or some of its
properties, that you want to audit,
with #Audited. For each audited
entity, a table will be created, which
will hold the history of changes made
to the entity. You can then retrieve
and query historical data without much
effort.
choose what you want to audit (on a per attribute basis)
make your own Revision Entity (that stores informations such as revision number, author, timestamp...)
Using Hibernate Envers for this decouples entities and revision data (in database and in your code).
You can do something like this simply by adding a version number to your domain class. I did something like this where the Id was a composite between an db assigned number and the version number, but I would advise against that. Use a normal surrogate key, and if you really want, make the [id, version] tuple a natural key.
You can actually version entire object graphs that way, just by ensuring that the version number is the same for all elements on the graph. You can then easily go back to any previous version.
You should write a lot of service tests to insure the integrity of the code that manages the version.

Categories