3 ms·
Correction. Not that I expect anyone will ever read this now the thread is done in HN, but I like to get it right. I sited Fowler, thinking _Patterns of Enterp
by cturner 16y ago
Correction. Not that I expect anyone will ever read this now the thread is done in HN, but I like to get it right.
I sited Fowler, thinking _Patterns of Enterprise Application Architecture_. I've checked and was mistaken. He does somewat similar stuff in QueryObject, but I'm thinking of a much higher-level concept.
I'll desccribe the relevant ORM patterns that I'd use. Most of my experience is with Apache Cayenne (which I strongly recommend), and some with Webobjects EOF before that.
This has been interesting to review. I haven't done serious work in either a compiled language or application development for years. It's interesting to come back at with fresh eyes.
= Entity
Your ORM will have tooling that will generate these classes for you from a tool or definition document.
There is a class per table in the schema. Each instance of Entity corresponds to a row of data in a table. Methods for foreign keys return objects for the linked class.
Your application would have classes Person, Organisation, etc.
ent.Person would have a method ((ent.Organistion) toOrganisationEntity()). end.Organistation would have a method ((List<ent.Person>) listPersonEntity()). Once you have an entity, the app can find related things via lookup.
Say you had the Organisation object, and wanted to know all the subjects that people for this company were enrolled in. You bounce through the graph. From Organisation you can get to Person, from there to JoinPersonSubject, from there to Subject.
An improvement on this is to have a separate base and application class. Your ORM generates the base class. You generate your app class and have it extend the base class. You put custom logic in the application class.
Example: Cayenne generates com.company.app.ent.base.Person. It has methods corresponding to each column in the person table. You create com.company.app.ent.Person (different package name) and have this extend the base class. You put convenience methods like ((String) getFullname()) in there.
You can then easily regenerate the base class without impacting your custom logic.
= DataAccessObject
(The summary sentence doesn't make much sense until you understand the concept, so I'll explain with example immediately afterwarss.)
Summary: You use a DataAccessObject for getting entrypoints into the graph of data held in the database.
Explanation: In Entity I described an example of bouncing around the graph. Say you had a user in an education system, and they wanted to get a list of all the organistaions associated with their office. You'd use a DAO to do this lookup.
Strangely, these patterns make a powerful coombination. You'd think that you'd need to add a bunch of extern
Your ORM probably won't generate these, but you should abstract them away into distinct classes like this rather than putting static methods in your
DAO functionality is commonly bolted into Entity classes as an afterthought using static methods. Ugly. Awful. Instead, consider DAO to be a distinct pattern, extending from an abstract base classs. The base class constructor will accept the current user as an argument. There will be a method that forms an ORM join between the current user and the
the current user you'd have common functionality such as a join between the
Unlike Entity, there is not a one-to-one mapping between data access objects and tables. You just create them as you need them. There might be an OrganisationDAO that has the query above, and some other queries in it. But then there might be a situation where you're doing a strange mega query across Organisation, Location and SalesTarget that doesn't seem to be specifically associated with any of those tables more than another. Here, you just create a new DAO.
= Session
The user's application session. In this you'll have a single instance of each DataAccessObject. That way your application can do lookups by going session().orgDao().listOrgWithAccountsAtUserOffice().