tags:

views:

114

answers:

4

Is there a commonly-accepted practice for designing java objects that are frequently loaded and saved to and from databases?

The approach that I'm using now is to have one main database object which opens a connection to the database. Anywhere in my application where I need to load or save objects, I create a source interface for loading and saving. For example, I might do something like this:

public interface CalendarSource {
  public Appointment[] getAppointmentsForMonth(int year, int month);
  public void saveAppointment(Appointment appointment);
}

Then I would implement that interface on the main database object. Any sub-data is also loaded at the same time into member objects inside the main objects. Like if there's a list of guests for each appointment. This works well, since all of the data I'm using comes from one of two databases, so I keep two database connections around, and each source is implemented by one of them.

The problem is that this just seems unwieldy at times. It's confusing how to handle ID values, since I really don't want to add them to my objects. It also requires one database connection to implement several different interfaces. Effectively, my database package has to rely on almost every package in the project because it implements all of the interfaces. This does make sense on a certain level, but I'm wondering if there's a better way.

There are two main reasons why I chose this architecture:

  • I'd like the objects that I use to not know that they are loaded or saved from a database. I might want to replace this database source in the future with flat files for portability.
  • I'd like to have a good package dependency hierarchy. The database code should be isolated so a change to the database schema can be easily updated to the code.

The one problem that I run into is what to do about ID values. Since the objects shouldn't know they are database objects, they shouldn't have an ID field in them. But, if I try to write an object to the database, and I don't have the ID value, how am I supposed to know if I should do an insert or an update?

I'm also concerned about having the database package extend everything throughout the whole project. I'm constantly passing these source interfaces around. I suppose that makes sense, too.

Maybe I'm just looking for some validation that I'm doing it right, and there's not some obvious simple solution here that I'm not seeing. Don't get me wrong - everything works just fine.

Any thoughts?

+4  A: 

I think the most universal pattern is the DAO pattern. That is, Data Access Object. Basically you define an interface which specifies the behavior (like basic crud operations, and specialized behavior for your domain) and then you provide implementations. For extra points you can use generics is java 5 and greater to write less code.

http://www.ibm.com/developerworks/java/library/j-genericdao.html

Its an important design choice to keep all persistence code in one layer of your application. It helps keep the code simple and clean.

From your post, you don't want to do what you are doing. Use Spring or equivalent because it will handle a lot of the code for you. It manages connections, transactions, etc.

Also, don't worry about having an ID field on your classes. While you might not consider it perfect, it makes life easier. Choose to fight the larger design fights, like doing TDD and keeping your design clean.

hvgotcodes
When I load and save this data to and from flat files, there won't be database ID's. It doesn't make sense to have a database ID field on the object. (but that doesn't mean I didn't put one in an object in one case where I absolutely needed it) I tend not to like 3rd party software for things like this, because they always seem to do tons of things I don't need. I just want a good design pattern that I can implement, really. Or, I want to be convinced that I should be using a 3rd party software -- and which one.
Erick Robertson
i didnt see the bit about flat files in the original question. I thought you had a db and might want to go to flat files in the future. Regardless, the DAO pattern is still applicable. You can have an implementation for a DB and an implementation for a file. Incidently, what you are describing is really a DAO pattern anyway.Yes, Spring is quite large, but they way I look at it is that they give you a lot of functionality for the tradeoff of including their jars. And they probably did a hell of a lot better job than any ordinary programmer could do.
hvgotcodes
I'm definitely going to spend some time reviewing Spring, Hibernate, iBatis, and JPA. I have no idea if I will switch to one of them or just steal an idea or two and add them to my implementation. I like spending the time to build something that works, is fairly straightforward, and is customized to our solution. Where there's a third party that's already done that, I do not hesitate to use it. I would use Joda or Trove as examples where I have embraced third party libraries.
Erick Robertson
+1  A: 

I say the easiest structure is generally something like

Create domain objects that have the fields you want.

Public class Appointment {
private Date appointmentDate;
private String locationName;
List<Person> appointmentAttendees;
}

Then you have a database that maps 1 field to 1 column... and throw it in Hibernate to go back and forth from object to database object.

Will that meet all your needs? Who knows. Depends what all you need :P

bwawok
I know how to structure the object. I'm more concerned with the design pattern for the interface to the database.
Erick Robertson
As I said, use hibernate (or similar). Then you just save it off to the DB with the supplied functions.
bwawok
+1  A: 

Do Not Roll Your Own.

Look at Hibernate, iBatis and JPA.

Toss a coin. (I like iBatis, but the other two are equally good)

Implement completely in the chosen technology.

Now that you've implemented something, you have learned the technology and can now make a rational choice to pursue an alternative or stick with the one you choose initially.

Important: Do Not Roll Your Own.

S.Lott
Why is it important not to roll my own? Is it for maintainability reasons? Which of those technologies is the most-used?
Erick Robertson
@Erick Robertson: Rolling your own is a maintenance nightmare. Other people have already **solved** this problem completely, and elegantly. The design patterns are well understood. It's solved. You don't need to do any more work on this, other folks have already done it. "Most Used"? As I said -- toss a coin.
S.Lott
@S.Lott you say that with a lot of conviction eh? I agree completely, unless this is some sort of school project where the objective is to learn.
hvgotcodes
@hvgotcodes: In my 30+ years of programming, I've learned that home-brewed solutions to standard problems just create larger problems. Less code is better. No code is best. Code less, reuse more.
S.Lott
I agree with S.Lott. The problem with homerolled solutions is that the distance between the firSt simple prototype and something finished is much bigger than newcomers think so they happily hack along and never get it finished.
Thorbjørn Ravn Andersen
I'm not opposed to a homerolled solution. We have experienced developers who know how to organize and document extensible code. Once the pattern has been established, it becomes fairly straightforward to build upon it. This also gives us a solution that works well for the way that we use data. We know it's fast and to the point. I agree with the "code less reuse more" philosophy, but I disagree with "less code more XML".
Erick Robertson
@Erick Robertson: Who said "less code more XML"? I don't get that. My point is to minimize home-brewed code. "a solution that works well for the way that we use data" is often not true. After all, you're asking for good design patterns. iBatis, JPA, and Hibernate are the **definitive** design patterns. Rather than "copy" their patterns, just use the projects and simplify your life. Focus on applications, not infrastructure, please.
S.Lott
This is how I understand what I'm reading here. I'm being told to use a 3rd party software so that I don't end up rewriting their code. So instead of writing code dealing with result sets, I write XML describing the data and the 3rd party library takes care of the details. That to me seems like less code more XML. Changing code maintenance into XML maintenance does not reduce maintenance, IMHO. I also think that you think I'm spending too much time on this. I'm not. I've hardly spent any time on this. I just thought it would be good to ask in case I was missing something easy.
Erick Robertson
@Erick Robertson: "Changing code maintenance into XML maintenance does not reduce maintenance" You're missing the point. There's less maintenance to begin with using someone else's ORM. The XML is touched only rarely. Your application deals -- trivially -- with persistent objects and you can focus on the application and the methods of the persistent objects. Not the DAO's, SQL and other database technology.
S.Lott
@Erick Robertson: "in case I was missing something easy". That's my point. Use someone else's ORM. It's the easiest way.
S.Lott
I'm reviewing the Hibernate API, sample code, and tutorials. This isn't easy. There are too many moving parts to coordinate, and it still doesn't solve the biggest problem I'm running into - the managing of database ID values and separation from the object model.
Erick Robertson
@Erick Robertson: "This isn't easy". That's why I like iBatis.
S.Lott
+2  A: 

Your approach forward 'one central database object' and 'sub-data is also loaded' seems a direction to good design.

However, as this is java in 2010 such problems as data storage and really all related stuff around are already implemented. Whats more you have specifications like JDBC, JPA and JDO and for these specs several implementations like Hibernate, Open JPA, EclipseLink...

E.g. JPA and Hibernate is a perfect choice! You will need an xml config file where you define your database configurations(http://docs.jboss.org/hibernate/core/3.3/reference/en/html/session-configuration.html).

You can define your persistent Java Class - DB Table mapping in that xml(http://docs.jboss.org/hibernate/core/3.3/reference/en/html/xml.html) or also by annotations(http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/).

You will use Hibernate Session/Entity manager to save your persistence objects state into tables. (http://docs.jboss.org/hibernate/stable/entitymanager/reference/en/html_single/)

For Id values: these are generated in most cases, there are several possible approach for the value generation.(http://docs.jboss.org/hibernate/core/3.3/reference/en/html/mapping.html#mapping-declaration-id)

You can stay independent from DB Tables, you can restructure, rename anytime as these can be reconfigured. For more complex changes you should check (http://docs.jboss.org/hibernate/stable/core/reference/en/html/inheritance.html)

If you change to file storage, no problem as your Java classes are Serializable classes you can save their state anytime into a File independent of the database implementation.(http://java.sun.com/developer/technicalArticles/Programming/serialization/)

Java World Hibernate Tutorial

gubra
So, I'm already adverse to XML and JBoss, but those are completely different discussions. We're not using J2EE - so no beans. I think that rules out JPA. The key here is that I want something simple. It should be able to be explained or understood in a couple lines of code. If I have to write XML config files for each object, and then paste in a huge block of code to make it work, in my opinion that becomes a maintenance nightmare.
Erick Robertson
Annotation based hibernate. Just do a config once and be done with it.
bwawok