You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ibatis.apache.org by Jeff Butler <je...@gmail.com> on 2006/10/10 19:45:27 UTC

Proposed Enhancement - Support Multiple Parameter Classes

Hi All,

We have an issue that I believe is quite common with enterprise databases.
Many (most) of the tables contain fields that are necessary for
insert/update, but those fields do not really belong in our domain objects.
These fields are often related to audit tracking in the tables (update
timestamp, update user, update process, etc.).

In my mind, these fields are DB trash that do not belong in domain objects.
However, if we build our POJOs without the DB trash, inserts and updates
become problematical.  We've tried these approaches to the problem:

1. Put every field in a Map for insert/update, pass the Map as parameter
object
2. Put the POJO in a Map, add the DB trash to the Map, pass the Map as a
parameter object
3. Create some special subclass of the POJO that adds the DB trash, then do
the get/set dance to populate the subclass and pass the subclass as a
parameter object
4. Create pseudo POJOs that exactly match the table, do the get/set dance
from our real POJOs to the table specific POJOs, and then fill in the DB
trash columns as appropriate in the table specific POJOs

Each of these approaches has a particular smell - sometimes forcing the use
of Maps, sometimes forcing the get/set dance, sometimes both.  I'm favoring
#4 right now, but still - it's not optimal.

My thought is that this whole issue could be elegantly solved if we allowed
multiple parameter classes like this:

<insert id="insertCustomer" parameterClass="Customer, DBTrash">
 ...
</insert>

and then we added special processing for supporting a List of parameter
objects passed in on the SqlMapClient methods.

What are your thoughts?  Have I missed some different and better way of
dealing with this issue?  Would this approach be too difficult to implement
in iBATIS?

Jeff Butler

Re: Proposed Enhancement - Support Multiple Parameter Classes

Posted by Jeff Butler <je...@gmail.com>.
Hi Richard,

It sounds like your taking the approach I labeled #3.  Did you ever consider
some kind of dynamic proxy?  That's also been on my list to consider.

There's obviously no good way to do this.  Hopefully we can come up with a
good idea by all thinking about it together.  Thanks for participating!

Jeff Butler

Re: Proposed Enhancement - Support Multiple Parameter Classes

Posted by Richard Sullivan <it...@gmail.com>.
Jeff you took the words outta my mouth.  Your idea gets a humble +1 from me.

I've no idea about IBATIS internals but I think Jeff is proposing something
which would greatly increase the usability of the mapping.

I' m working on a team project where the persistence layer is my baby and I
hate exposing details of the persistence layer to the business layers.

For those who might see the problem I will briefly describe the shenanigens
I have used to workaround it.

For DB-trash think PK values and some information that I need in order to be
able how to sort out the mess when I read it back (for example a vector
position index value when reading back a vector of domain objects so that
the order is preserved).

<shenanigens>
I ended up writing PersistentX, PersistentY etc. where X and Y are the
domain objects and the PersistentX looks like this:

public class PersistenX extends {
    DBTrashValueClass dbTrash;

    // loads of getters/setters() each delegating to dbTrash
    long getPKCol1() { return dbTrash.getPKCol1(); }
    long getPKCol2() { return dbTrash.getPKCol2(); }
    int getOrderPosition() { return dbTrash.getOrderPosition(); }
    ....
}

Before the persistence layer  writes a domain object I have to  instantiate
a new "Persistent" object corresponding to the particular domain object,
copy all attributes of the domain object to the "Persistent" version (I do
this using Commons PropertyUtils), next I copy in all the DB persistence
control information (). After all this I can pass the PersistentX as a
parameter class for my INSERT.
</shenanigens>

This is a LOT of mucking around and is not a great example of object
oriented programming.

I did consider using aspects to somehow introduce the db-trash into the
domain objects rather than misusing inheritance for this task.  For my
present project this is a no-no (project manager wants a SIMPLE solution)
but if the IBATIS framework did the aspect magic then I probably would have
jumped at it.  I think Hibernate does something similar using byte-code
manipulation in some circumstances but I digress.  I'm not a great fan of
such tricks but they could be made optional.

Another enhancement that would probably make a huge difference would to be
able to use OGNL expressions to access nested properties of the parameter
class since often domain objects are nested.

Thanks,
Richard

Re: Proposed Enhancement - Support Multiple Parameter Classes

Posted by Clinton Begin <cl...@gmail.com>.
+1.  I understand your problem and I understand the proposed solution.

But...

At this time, you can achieve this using a HashMap:

params.put("Customer", customer);
params.put("DBTrash", dbTrash);

sqlMap.insert("statement", params)

<insert ... paramterClass="HashMap">

That said, I've been thinking iBATIS 3 should take a multiple parameter
support approach.  This may increase the verbosity of the Java API and the
XML files, but it would clean up the mess above.  And it might be possible
to support the APIs for single and multiple parameters...

Anyway.  Long story short, I agree for iBATIS 3, I'd like to see this.  But
for iBATIS 2.x, I don't think we should add this...it might cut accross too
many seams.

Cheers,
Clinton




On 10/10/06, Jeff Butler <je...@gmail.com> wrote:
>
> Hi All,
>
> We have an issue that I believe is quite common with enterprise
> databases.  Many (most) of the tables contain fields that are necessary for
> insert/update, but those fields do not really belong in our domain objects.
> These fields are often related to audit tracking in the tables (update
> timestamp, update user, update process, etc.).
>
> In my mind, these fields are DB trash that do not belong in domain
> objects.  However, if we build our POJOs without the DB trash, inserts and
> updates become problematical.  We've tried these approaches to the problem:
>
> 1. Put every field in a Map for insert/update, pass the Map as parameter
> object
> 2. Put the POJO in a Map, add the DB trash to the Map, pass the Map as a
> parameter object
> 3. Create some special subclass of the POJO that adds the DB trash, then
> do the get/set dance to populate the subclass and pass the subclass as a
> parameter object
> 4. Create pseudo POJOs that exactly match the table, do the get/set dance
> from our real POJOs to the table specific POJOs, and then fill in the DB
> trash columns as appropriate in the table specific POJOs
>
> Each of these approaches has a particular smell - sometimes forcing the
> use of Maps, sometimes forcing the get/set dance, sometimes both.  I'm
> favoring #4 right now, but still - it's not optimal.
>
> My thought is that this whole issue could be elegantly solved if we
> allowed multiple parameter classes like this:
>
> <insert id="insertCustomer" parameterClass="Customer, DBTrash">
>  ...
> </insert>
>
> and then we added special processing for supporting a List of parameter
> objects passed in on the SqlMapClient methods.
>
> What are your thoughts?  Have I missed some different and better way of
> dealing with this issue?  Would this approach be too difficult to implement
> in iBATIS?
>
> Jeff Butler
>
>

Re: Proposed Enhancement - Support Multiple Parameter Classes

Posted by Larry Meadors <lm...@apache.org>.
Yeah, something like that..I hadn't thought at all about the syntax. :-)

Larry


On 10/10/06, Jeff Butler <je...@gmail.com> wrote:
> Hi Larry,
>
> If I understand correctly what your suggesting, I'm thinking we could do
> something like this:
>
> 1. Put a Map in ThreadLocal in the SqlMapClient
>
> 2.  Add SqlMapCient methods like:
> - clearThreadLocalMap()
> - putThreadLocalData(String key, Object value)
>
> 3. Add some syntax to access these values in an SqlMap like this:
> <insert id=InsertCustomer" class="customer">
>   insert into customer (id, desc, audit_id)
>   values (#id#, #desc#, #TL:audit_id#)
> </insert>
>
> Is that right?  That would certainly address my issue - and I think it would
> be easier to implement that what I proposed.  I think I like it.
>
> Jeff Butler
>
>
>
>
>
> On 10/10/06, Larry Meadors <lm...@apache.org> wrote:
> > IMO, it doesn't fit with the iBATIS philosophy.
> >
> > There are as many solutions to this as there are projects, and making
> > a simple solution to this problem is not terribly likely.
> >
> > I tend to put as much of that in the DAO (via threadlocal storage) or
> > in the database itself (via triggers, etc) as I can. That keeps it out
> > of the application pretty well. It might be cool to be able to get to
> > static data from a mapped statement - so like if i create a static
> > method on a ThreadLocal to get the user name, etc...
> >
> > Just my $0.02 on it. :-)
> >
> > Larry
> >
> >
> >
>

Re: Proposed Enhancement - Support Multiple Parameter Classes

Posted by Jeff Butler <je...@gmail.com>.
Hi Larry,

If I understand correctly what your suggesting, I'm thinking we could do
something like this:

1. Put a Map in ThreadLocal in the SqlMapClient

2.  Add SqlMapCient methods like:
- clearThreadLocalMap()
- putThreadLocalData(String key, Object value)

3. Add some syntax to access these values in an SqlMap like this:
<insert id=InsertCustomer" class="customer">
  insert into customer (id, desc, audit_id)
  values (#id#, #desc#, #TL:audit_id#)
</insert>

Is that right?  That would certainly address my issue - and I think it would
be easier to implement that what I proposed.  I think I like it.

Jeff Butler




On 10/10/06, Larry Meadors <lm...@apache.org> wrote:
>
> IMO, it doesn't fit with the iBATIS philosophy.
>
> There are as many solutions to this as there are projects, and making
> a simple solution to this problem is not terribly likely.
>
> I tend to put as much of that in the DAO (via threadlocal storage) or
> in the database itself (via triggers, etc) as I can. That keeps it out
> of the application pretty well. It might be cool to be able to get to
> static data from a mapped statement - so like if i create a static
> method on a ThreadLocal to get the user name, etc...
>
> Just my $0.02 on it. :-)
>
> Larry
>
>
>

Re: Proposed Enhancement - Support Multiple Parameter Classes

Posted by Larry Meadors <lm...@apache.org>.
IMO, it doesn't fit with the iBATIS philosophy.

There are as many solutions to this as there are projects, and making
a simple solution to this problem is not terribly likely.

I tend to put as much of that in the DAO (via threadlocal storage) or
in the database itself (via triggers, etc) as I can. That keeps it out
of the application pretty well. It might be cool to be able to get to
static data from a mapped statement - so like if i create a static
method on a ThreadLocal to get the user name, etc...

Just my $0.02 on it. :-)

Larry


On 10/10/06, Jeff Butler <je...@gmail.com> wrote:
> Hi All,
>
> We have an issue that I believe is quite common with enterprise databases.
> Many (most) of the tables contain fields that are necessary for
> insert/update, but those fields do not really belong in our domain objects.
> These fields are often related to audit tracking in the tables (update
> timestamp, update user, update process, etc.).
>
> In my mind, these fields are DB trash that do not belong in domain objects.
> However, if we build our POJOs without the DB trash, inserts and updates
> become problematical.  We've tried these approaches to the problem:
>
> 1. Put every field in a Map for insert/update, pass the Map as parameter
> object
> 2. Put the POJO in a Map, add the DB trash to the Map, pass the Map as a
> parameter object
> 3. Create some special subclass of the POJO that adds the DB trash, then do
> the get/set dance to populate the subclass and pass the subclass as a
> parameter object
> 4. Create pseudo POJOs that exactly match the table, do the get/set dance
> from our real POJOs to the table specific POJOs, and then fill in the DB
> trash columns as appropriate in the table specific POJOs
>
> Each of these approaches has a particular smell - sometimes forcing the use
> of Maps, sometimes forcing the get/set dance, sometimes both.  I'm favoring
> #4 right now, but still - it's not optimal.
>
> My thought is that this whole issue could be elegantly solved if we allowed
> multiple parameter classes like this:
>
> <insert id="insertCustomer" parameterClass="Customer, DBTrash">
>  ...
> </insert>
>
> and then we added special processing for supporting a List of parameter
> objects passed in on the SqlMapClient methods.
>
> What are your thoughts?  Have I missed some different and better way of
> dealing with this issue?  Would this approach be too difficult to implement
> in iBATIS?
>
> Jeff Butler
>

Re: Proposed Enhancement - Support Multiple Parameter Classes

Posted by Richard Sullivan <it...@gmail.com>.
>>If your enterprise requires that you display audit data then what is it
that is not part of the domain?
Audit data is a nasty grey area.   Auditing is a sort of shadow domain to
the real application domain since it generally is interesting only to people
who administer or control the application rather than to the primary users.
For this reason audit applications are often implemented separately to the
systems that they audit.

For me real domain data is either typed in by end-users (think of a TODO
list application) or is collected by the system and presented to them as a
service (stock-price information).

Richard

Re: Proposed Enhancement - Support Multiple Parameter Classes

Posted by Jeff Butler <je...@gmail.com>.
Not 10 different databases, ten different tables in the same database.
Think header/detail records - but much more complex.

If you've never worked with an independant DBA group whose design
philosophies are maintained solely at their own discretion - without needing
to take the application needs into account - then the problem is is hard to
understand.  The tables are often super (hyper?) normalized and auditing is
quite complex.

Some of our report queries join 25 tables!  It's not pretty, but it is
reality :)

Jeff Butler



On 10/10/06, Brandon Goodin <br...@gmail.com> wrote:
>
> I guess I don't completely understand your issue. Do you have 10 different
> SqlMpas instantiated that call 10 different database and may share 1 domain
> object that needs to write to all of them? This souns extreme to me.
>
>
>

Re: Proposed Enhancement - Support Multiple Parameter Classes

Posted by Brandon Goodin <br...@gmail.com>.
I guess I don't completely understand your issue. Do you have 10 different
SqlMpas instantiated that call 10 different database and may share 1 domain
object that needs to write to all of them? This souns extreme to me.

On 10/10/06, Jeff Butler <je...@gmail.com> wrote:
>
> It's not for display - it's only required for update/insert.
>
> Maybe I need to clarify what I mean by an "enterprise database".  In our
> situation, this means "separate DBA and database design group - not under
> our control".  So things like stored procedures, extra triggers, and table
> design changes aren't really options for us.  Most truly enterprise
> databases have many different applications hitting them and they maintain
> their own sets of standards.  They usually aren't open to changing things
> just to make it easier for one client application.
>
> As to whether these fields belong in the POJOs or not, this is certainly
> open to debate.  An issue with it is this - one domain object could map to
> many more than one DB table (we have cases where a domain object maps to
> upwards of 10 tables).  Maintaining all the DB trash for these 10 different
> tables in my domain object makes the object very tightly coupled with the DB
> - might as well just use classes that exactly match the tables if we're
> going there (this is sort of what I'm doing anyway).
>
> I'm intrigued with Larry's idea of accessing static ThreadLocal data in a
> mapped statement.  I wonder what the syntax for that would look like?
>
> Jeff Butler
>
>
>
> On 10/10/06, Brandon Goodin <br...@gmail.com> wrote:
> >
> > If your enterprise requires that you display audit data then what is it
> > that is not part of the domain? It is domain relevant data. Just because it
> > is shared among all database tables doesn't make it non-domain. For auditing
> > i generally have a couple of different levels. One is "single generation"
> > and the other "historical". When handling "single generation update/insert
> > auditing, I add a date and user field to my POJOs (one of each for insert
> > and update). For "historical" auditing, I place a trigger that writes to
> > another table whenever a record is updated/deleted. This maintains a truly
> > historical auditing trail. I would encourage you to just add the "single
> > generation" audit fields to your POJOs and be done with it.
> >
> > Brandon
> >
>
>

Re: Proposed Enhancement - Support Multiple Parameter Classes

Posted by Jeff Butler <je...@gmail.com>.
It's not for display - it's only required for update/insert.

Maybe I need to clarify what I mean by an "enterprise database".  In our
situation, this means "separate DBA and database design group - not under
our control".  So things like stored procedures, extra triggers, and table
design changes aren't really options for us.  Most truly enterprise
databases have many different applications hitting them and they maintain
their own sets of standards.  They usually aren't open to changing things
just to make it easier for one client application.

As to whether these fields belong in the POJOs or not, this is certainly
open to debate.  An issue with it is this - one domain object could map to
many more than one DB table (we have cases where a domain object maps to
upwards of 10 tables).  Maintaining all the DB trash for these 10 different
tables in my domain object makes the object very tightly coupled with the DB
- might as well just use classes that exactly match the tables if we're
going there (this is sort of what I'm doing anyway).

I'm intrigued with Larry's idea of accessing static ThreadLocal data in a
mapped statement.  I wonder what the syntax for that would look like?

Jeff Butler



On 10/10/06, Brandon Goodin <br...@gmail.com> wrote:
>
> If your enterprise requires that you display audit data then what is it
> that is not part of the domain? It is domain relevant data. Just because it
> is shared among all database tables doesn't make it non-domain. For auditing
> i generally have a couple of different levels. One is "single generation"
> and the other "historical". When handling "single generation update/insert
> auditing, I add a date and user field to my POJOs (one of each for insert
> and update). For "historical" auditing, I place a trigger that writes to
> another table whenever a record is updated/deleted. This maintains a truly
> historical auditing trail. I would encourage you to just add the "single
> generation" audit fields to your POJOs and be done with it.
>
> Brandon
>

Re: Proposed Enhancement - Support Multiple Parameter Classes

Posted by Brandon Goodin <br...@gmail.com>.
If your enterprise requires that you display audit data then what is it that
is not part of the domain? It is domain relevant data. Just because it is
shared among all database tables doesn't make it non-domain. For auditing i
generally have a couple of different levels. One is "single generation" and
the other "historical". When handling "single generation update/insert
auditing, I add a date and user field to my POJOs (one of each for insert
and update). For "historical" auditing, I place a trigger that writes to
another table whenever a record is updated/deleted. This maintains a truly
historical auditing trail. I would encourage you to just add the "single
generation" audit fields to your POJOs and be done with it.

Brandon

On 10/10/06, Jeff Butler <je...@gmail.com> wrote:
>
> Hi All,
>
> We have an issue that I believe is quite common with enterprise
> databases.  Many (most) of the tables contain fields that are necessary for
> insert/update, but those fields do not really belong in our domain objects.
> These fields are often related to audit tracking in the tables (update
> timestamp, update user, update process, etc.).
>
> In my mind, these fields are DB trash that do not belong in domain
> objects.  However, if we build our POJOs without the DB trash, inserts and
> updates become problematical.  We've tried these approaches to the problem:
>
> 1. Put every field in a Map for insert/update, pass the Map as parameter
> object
> 2. Put the POJO in a Map, add the DB trash to the Map, pass the Map as a
> parameter object
> 3. Create some special subclass of the POJO that adds the DB trash, then
> do the get/set dance to populate the subclass and pass the subclass as a
> parameter object
> 4. Create pseudo POJOs that exactly match the table, do the get/set dance
> from our real POJOs to the table specific POJOs, and then fill in the DB
> trash columns as appropriate in the table specific POJOs
>
> Each of these approaches has a particular smell - sometimes forcing the
> use of Maps, sometimes forcing the get/set dance, sometimes both.  I'm
> favoring #4 right now, but still - it's not optimal.
>
> My thought is that this whole issue could be elegantly solved if we
> allowed multiple parameter classes like this:
>
> <insert id="insertCustomer" parameterClass="Customer, DBTrash">
>  ...
> </insert>
>
> and then we added special processing for supporting a List of parameter
> objects passed in on the SqlMapClient methods.
>
> What are your thoughts?  Have I missed some different and better way of
> dealing with this issue?  Would this approach be too difficult to implement
> in iBATIS?
>
> Jeff Butler
>
>