On Sat, Oct 1, 2011 at 8:45 AM, Matthew Woodward <[email protected]> wrote: > And be SURE and read the "ORM is the Vietnam of Computer Science" link Sean > provided. Required reading if you're even considering using ORM.
And Ted Neward's original article, linked from Jeff Atwood's blog, if you want more depth. > ORM is a big, hairy, complex problem to solve and even with a best-of-breed > tool such as Hibernate, if you do decide to use it you better buy a couple > of the big-ass books on it (Java Persistence With Hibernate is an excellent > one) and learn the tool inside and out. Agreed. I first used Hibernate with Spring and Groovy back in 2008 to create the back end of a Flex/AIR app. We ran into a lot of the problems that CFers are now seeing with the Hibernate-backed ORM (session management, detached objects, bidirectional relationship complexities). The lure is great: "never write SQL again" but Hibernate only differs from arf!, objectBreeze, Reactor, Transfer etc by being more robust and somewhat more performant. Those problems are core to ORM because it's an abstraction that tries to hide the mapping between two very different models (objects and tables). At World Singles, we started out with Reactor back in 2009 (Reactor lead, Mark Drew, was involved with the project before I got involved, which was why Reactor was picked over Transfer - but the decision to use ColdBox + ColdSpring + an ORM had been made by the then CTO) and we're still slowly weaning ourselves off it because of performance (primarily). As the project has progressed, I created a very simple object mapper that handled relationships by convention**, instead of within the object mapper itself. That helped, taking care of CRUD while pushing object relationship management up into the application model. Later I created an even simpler mapper in Clojure, as a thin CRUD layer around the clojure.java.jdbc library, and moved to data-as-maps (structs in CFML). A thin "bean" wrapper around a struct provided the benefits of objects and perpetuated the convention-based relationship handling. The result is great performance (structs and records are essentially identical so there's really no "mapping" so the generated SQL is about as simple as it can be), good flexibility and the ability to expose an object-like API even over complex joined queries (using the Iterating Business Object pattern which seems to be attributed to Peter Bell). **The convention is implemented by onMissingMethod() as follows: * If you ask a Thing for getFooIterator() (or getFooArray()) and there's no field called fooIterator (or fooArray), then a query is done on the foo table, looking for bar.thingId = Thing.getId() and the result is stored in Thing.fooIterator (or Thing.fooArray) as an IBO (or array of "objects"). * If you ask a Thing for getBar() and there's no field called bar but a field called barId exists, then a query is done on the bar table, looking for bar.id = Thing.getBarId() and the result is stored in Thing.bar as an "object". If you want to avoid the on-demand object-by-object joins, you can do a direct SQL query and still wrap it in an IBO of the base object type. The wrapper handles dirty data by writing to one struct in the "bean" and reading from the dirty struct or the "clean" struct as appropriate - that way the whole dirty data struct can be persisted easily as an update on just the columns that have changed. The wrapper exposes basic Active Record methods and delegates to the Clojure CRUD wrapper around clojure.java.jdbc. The nice thing about this approach has been that the actual storage is encapsulated in our CRUD wrapper and we are now able to migrate data from MySQL to MongoDB without changing application code that depends only on the mapper (obviously code that does raw SQL needs to be reworked). Because the relationships are already in the "application layer" (in the IBO / bean wrapper), the convention-based relationship handling still works even when one object is stored in a table in MySQL and the related objecta are stored in MongoDB! > The best way to not have to write SQL for your applications? Use a NoSQL > database. :-) Totally different topic but I've been using CouchDB a great > deal lately and that actually *removes* the object-relational impedance > mismatch as opposed to giving you a complex tool to deal with it for you. > That to me has felt like a huge weight lifted off my applications, whereas > ORM never felt that way. Agreed. And that's part of what's driving our migration from MySQL to MongoDB. We also like the freedom to store structured data (an arbitrary struct containing arrays / structs can be stored directly in MongoDB - which is also true for Clojure maps and vectors) and the ability to store additional fields for some objects without needing to worry about schema structure or migrations. > Or if you do your homework and decide you love Hibernate you can write your > model in Java. Ultimately that'd probably give you far fewer headaches. And be much more performant than using CFML and the built-in ORM :) At World Singles, we're moving to an MVC architecture where the Model is Clojure and the View-Controller is CFML (and will ultimately be FW/1 + DI/1 instead of ColdBox + ColdSpring). Although, as a side project, I'm also porting FW/1 to Clojure and if I can cleanly solve the View templating aspect, we may ultimately migrate entirely to Clojure... -- Sean A Corfield -- (904) 302-SEAN An Architect's View -- http://corfield.org/ World Singles, LLC. -- http://worldsingles.com/ Railo Technologies, Inc. -- http://www.getrailo.com/ "Perfection is the enemy of the good." -- Gustave Flaubert, French realist novelist (1821-1880) -- official tag/function reference: http://openbd.org/manual/ mailing list - http://groups.google.com/group/openbd?hl=en
