tags:

views:

55

answers:

1

I'm trying to put some new functionality into an existing app that uses iBatis but I'm a little stuck with one of the design decisions.

There is an existing class (call it class A) which I want to add some new fields to. These fields will be of type B.

The query will join B via an outer join.

So it will be something like

public class A {

   //... existing fields
   private List<B> bList; // may use a Map rather than a list?

   // etc.
}

public class B {
   private int id; // primary key
   private int type;
   private String description;

   // etc.

}

I'm using this in a web app. On the first page I want to return a list of "A's", and then put links beside for the B's.

Eg:

LinktoRecordA1 - LinktoB1 LinktoB2 LinktoB3
LinktoRecordA2 - LinktoB1          LinktoB3
LinktoRecordA3 - LinktoB1 LinktoB2 LinktoB3
LinktoRecordA4 

etc.

(NB: Record A4 has no links to any B's - hence the outer join mentioned above)

In the initial fetch of the "A's", I only want to know that the B record exists, and what it's primary key is to present the link through to the B detail record. So my problem is, how do I do this without creating a fully populated list of "B's" on the "A" object?

A: 

Regarding your comment:

How else should I do it? I think what I'm having trouble understading is 
this- should I return a list of "A" objects with only minimal data 
populated, or would should I create some kind of new object?

In situations like the one you describe (when a list is returned and the user can select something from it), I have noticed that the user usually selects one or two records to see more details. In this case you end up returned a list of fully populated objects for nothing.

In that case, what I do, is fallback to just select object identifiers instead of full-fledged objects.

So you could create a new class with only this data:

public class C {
  private Integer idForA;
  private List<Integer> listOfIdsForB = new ArrayList<Integer>();
  //...
}

You then write your query with an outer join to return A's and B's identifiers and return a result similar to this:

IDtoRecordA1 | IDtoB1 
IDtoRecordA1 | IDtoB2 
IDtoRecordA1 | IDtoB3

IDtoRecordA2 | IDtoB1          
IDtoRecordA2 | IDtoB3
IDtoRecordA3 | IDtoB1 

IDtoRecordA3 | IDtoB2 
IDtoRecordA3 | IDtoB3

IDtoRecordA4 | null

At this stage the groupBy attribute of the resultMap tag comes in handy to transform the result in a list of C objects containing this:

C1: IDtoRecordA1, [IDtoB1, IDtoB2, IDtoB3]
C2: IDtoRecordA2, [IDtoB1, IDtoB3]
C3: IDtoRecordA3, [IDtoB1, IDtoB2, IDtoB3]
C4: IDtoRecordA4, []

This is also very useful in avoiding N+1 queries. You may already be doing this when you return A objects with list of B’s, but if you are using separate queries to retrieve the list (i.e select attribute on result tag), than I suggest you take a look at the "Avoiding N+1 Selects" sections in the iBatis Data Mapper developer guide, to minimize the number of queries needed to return the data.

Bottom line is...

...if you handle a large volume of data, then returning full loaded objects just to display a small amount of info, is probably overkill.

..on the other hand, if you handle a small amount of data, introducing another class that handles the IDs will probably complicate the things, so you might just as well return full objects of A’s and B’s (but avoiding N+1 queries of course).

dpb