Besides ORM ...
If you use the rs.getString and rs.getInt routines, you can, of course, lighten your maintenance load by relying on named columns rather than column numbers.
In particular, rs.getInt ("id"), and not rs.getInt (1), for example.
It’s rare that I had the actual data type of the column change, so further SQL maintenance is nothing more than adding new columns that were made to the table, and you can just bind them to the end of your monster, link the list in each of you small objects DAO.
Then you then accept this idiom of using column names and extend it to a plan for using consistent names and, at the same time, “unique” names. The goal is that each column in your database has a unique name associated with it. Theoretically, it could be as simple (albeit verbose) as tablename_columnname, so if you have a table called "member", the column name is "member_id" for the id column.
What do you buy?
He buys you the opportunity to use your common DAOs on any “valid” result set.
A “valid” result set is a result set with columns using a unique specification of names.
So you get "select id member_id, name member_name from member, where id = 1".
Why do you need this? Why bother?
Because then your associations become trivial.
PreparedStatement = con.prepareStatement("select m.id member_id, m.name member_name, p.id post_id, p.date post_date, p.subject post_subject from member m, post p where m.id = p.member_id and m.id = 123"); ResultSet rs = ps.executeQuery(); Member m = null; Post p = null; while(rs.next()) { if (m == null) { m = MemberDAO.createFromResultSet(rs); } p = PostDAO.createFromResultSet(rs); m.addPost(p); }
Look, here the binding logic does not care about the contents of the result set, since it is only interested in the columns that it cares about.
In your DAOs, you make them a little smart in ResultSet. It turns out that if you do "rs.getInt (" member_id "), and member_id is not actually executed BE in the result set, you will get a SQLException.
But with a little work, using ResultSetMetaData, you can perform a quick preliminary check (selecting all the column names in front), and instead of calling “rs.getInt” you can call “baseDAO.getInt”, which processes this data for you, so as not to get an exception .
The beauty is that once you do this, you can easily get incomplete DAOs.
PreparedStatement = con.prepareStatement("select m.id member_id from member m where m.id = 123"); ResultSet rs = ps.executeQuery(); Member m = null; if (rs.next()) { m = MemberDAO.createFromResultSet(rs); }
Finally, this is a really (really) trivial bit of scripting (using, say, AWK) that can take bean properties and convert it to the correct code binding code for the source DAO. A similar script can easily take an SQL table statement and convert it to a Java bean (at least the basic elements), which your IDE then converts to a flurry of getters / seters.
By centralizing the binding code in the DAO, the service actually happens almost nothing, since it has changed in one place. Using partial bindings, you can mercilessly abuse them.
PreparedStatement = con.prepareStatement("select m.name member_name, max(p.date) post_date from member m, post p where post.member_id = m.id and m.id = 123"); ResultSet rs = ps.executeQuery(); Member m = null; Post p = null; if (rs.next()) { m = MemberDAO.createFromResultSet(rs); p = MemberDAO.craateFromResultSet(rs); } System.out.println(m.getName() + " latest post was on " + p.getDate());
Your burden moving forward is mostly writing SQL, but even that isn’t terrible. There are not many differences between writing SQL and EQL. Reason, this is partly due to the need to write a select statement with the number of columns in milliseconds, since you cannot (and should not) use "select * from ..." (select * always (ALWAYS) leads to a problem, IME).
But this is only a reality. However, I found that (if you are not reporting), this problem simply does not happen much. This happens at least once for most tables, but it happens more than once and again and again. And, of course, after you do this once, you can “cut and paste” your path to glory or reorganize it (ie sql = "select" + MemberDAO.getAllColumns () + "," + PostDAO. getAllColumns () + "from member m, post p").
Now I like JPA and ORM, I find them useful, but I also find them PITA. There are certain love / hate relationships that occur there. And when everything goes smoothly, boy, it's smooth. But when it becomes stony, boy. Then it can get ugly. In general, however, I recommend them.
But if you are looking for a "light" non-structure, this technique is useful, practical, low overhead and gives you great control over your needs. There is simply no black magic or dark matter between your queries and your database, and when something doesn’t work, this is not some secret misunderstanding of the framework or case problems if someone has 100K lines of code, but rather, the error is your SQL - where does it belong.