Quite a dilemma

R

Rizwan

I have 2 classes "ClassA" (mapped to TableA) and "ClassB" (mapped to
TableB). There is many-to-many relationship between these classes which is
represented by "ClassAB" (mapped to TableAB). ClassAB is a little bit more
than just relationship between ClassA and ClassB so we go with a seperate
class.

public class ClassA {
private int classAId;
private Set classABs = new HashSet(); // of type ClassAB
...
}
public class ClassB {
private int classBId;
private Set classABs = new HashSet(); // of type ClassAB
...
}
public class ClassAB {
private int classABId;
private ClassA classA;
private ClassB classB;
...
}


I have these DAO methods:

public ClassA getClassAById( int classAId );
public ClassB getClassBById( int classBId );
public ClassAB getClassABById( int classABId );
public Set getClassABsByClassA( ClassA classA );
public Set getClassABsByClassB( ClassB classB );


When I call "ClassA getClassAById( int classAId )" method, first I retrieve
data from TableA, populate it in ClassA object and then I call the "Set
getClassABsByClassA( ClassA classA )" method. This method retreive data from
TableAB, populate it in ClassAB objects and put them in a Set and then
returns the Set. Then the "ClassA getClassAById( int classAId )" set that
Set in the ClassA object and then returns the ClassA object.

Problem is that "Set getClassABsByClassA( ClassA classA )" method also tries
to resolve all the references in ClassAB. Since ClassAB has 2 references
ClassA and ClassB so it retrieves them as well. So for resolving reference
to ClassA it calls "ClassA getClassAById( int classAId )" method. The result
is a loop:
* "ClassA getClassAById( int classAId )" calls "Set getClassABsByClassA(
ClassA classA )"
* "Set getClassABsByClassA( ClassA classA )" calls "ClassA getClassAById(
int classAId )"

Am I doing something wrong? Or is it how it is supposed to work? Please
reply.

Thanks
 
O

Oliver Wong

Rizwan said:
I have 2 classes "ClassA" (mapped to TableA) and "ClassB" (mapped to
TableB). There is many-to-many relationship between these classes which is
represented by "ClassAB" (mapped to TableAB). ClassAB is a little bit more
than just relationship between ClassA and ClassB so we go with a seperate
class.

public class ClassA {
private int classAId;
private Set classABs = new HashSet(); // of type ClassAB
...
}
public class ClassB {
private int classBId;
private Set classABs = new HashSet(); // of type ClassAB
...
}
public class ClassAB {
private int classABId;
private ClassA classA;
private ClassB classB;
...
}


I have these DAO methods:

public ClassA getClassAById( int classAId );
public ClassB getClassBById( int classBId );
public ClassAB getClassABById( int classABId );
public Set getClassABsByClassA( ClassA classA );
public Set getClassABsByClassB( ClassB classB );


When I call "ClassA getClassAById( int classAId )" method, first I
retrieve data from TableA, populate it in ClassA object and then I call
the "Set getClassABsByClassA( ClassA classA )" method. This method
retreive data from TableAB, populate it in ClassAB objects and put them in
a Set and then returns the Set. Then the "ClassA getClassAById( int
classAId )" set that Set in the ClassA object and then returns the ClassA
object.

Problem is that "Set getClassABsByClassA( ClassA classA )" method also
tries to resolve all the references in ClassAB. Since ClassAB has 2
references ClassA and ClassB so it retrieves them as well. So for
resolving reference to ClassA it calls "ClassA getClassAById( int
classAId )" method. The result is a loop:
* "ClassA getClassAById( int classAId )" calls "Set getClassABsByClassA(
ClassA classA )"
* "Set getClassABsByClassA( ClassA classA )" calls "ClassA
getClassAById( int classAId )"

Am I doing something wrong? Or is it how it is supposed to work? Please
reply.

Your class names and method names are really confusing, and you don't
specify in which class the DAO methods are defined. Try posting a SSCCE
(http://www.physci.org/codes/sscce.jsp) and it might be easier to help you.

- Oliver
 
R

Rizwan

how about now :

I have 2 classes "Location" (mapped to TableA) and "Department" (mapped to
TableB). There is many-to-many relationship between these classes which is
represented by "LocDept" (mapped to TableAB). LocDept is a little bit more
than just relationship between Location and Department so we go with a
seperate
class.

public class Location {
private int locationId;
private Set locDepts = new HashSet(); // of type LocDept
...
}
public class Department {
private int departmentId;
private Set locDepts = new HashSet(); // of type LocDept
...
}
public class LocDept {
private int locDeptId;
private Location location;
private Department department;
...
}


I have these DAO methods:

public Location getLocation( int locationId ); // in
LocationDAO.java
public Department getDepartment( int departmentId ); // in
DepartmentDAO.java
public LocDept getLocDept( int locDeptId ); // in
LocDeptDAO.java
public Set getLocDeptsByLocation( int locationId ); // in
LocDeptDAO.java
public Set getLocDeptsByDepartment( int departmentId ); // in
LocDeptDAO.java


When I call "Location getLocation( int locationId )" method, first I
retrieve
data from TableA, populate it in Location object and then I call the "Set
getLocDeptsByLocation( int locationId )" method. This method retreive data
from TableAB, populate it in LocDept objects and put them in a Set and then
returns the Set. Then the "Location getLocDept( int locationId )" method set
that
Set in the Location object and then returns the Location object.

Problem is that "Set getLocDeptsByLocation( int locationId )" method also
tries
to resolve all the references in LocDept. Since LocDept has 2 references
Location and Department so it retrieves them as well. So for resolving
reference
to Location it calls "Location getLocation( int locationId )" method. The
result
is a loop:
* "Location getLocation( int locationId )" calls "Set getLocDeptsByLocation(
int locationId )"
* "Set getLocDeptsByLocation( int locationId )" calls "Location getLocation(
int locationId )"

Am I doing something wrong? Or is it how it is supposed to work? Please
reply.

Thanks
 
R

Roedy Green

Problem is that "Set getClassABsByClassA( ClassA classA )" method also tries
to resolve all the references in ClassAB.

"resolving the references" usually refers to something that happens at
compile time. I think you are referring to some sort of analogous
runtime behaviour. Some real code would go a long way to explaining
what you mean by that phrase.
 
C

Chris Uppal

Andrew said:
1) posting code snippets when an SSCCE was requested/needed..

Don't be silly, Andrew, this is a code structuring problem, not a bug needing
an SCCE for demonstration.

An SCCE would be pointless, complicated (are you going to set up a databse on
your machine to try out Rzwan's code ?), and /much/ more difficult to follow
than a carefully cut-down example -- which Rizwan has in fact provided.

-- chris
 
A

Andrea Desole

A lot depends on your specific situation. I think, if I understand
correctly, that I would probably would implement classA, classB and
classAB just to keep the ids of the objects they are related to. When,
for example, a classA needs the classAB objects, they are retrieved from
the database, but just with the ids of classA and classB; the real
objects can be retrieved later if necessary.
I would also consider implementing a cache, so that all the objects you
get from the database with the same id actually refer to the same instance.
Or you can just read all your objects at the beginning (if they are not
too many), or use hibernate...
 
C

Chris Uppal

Rizwan said:
how about now :
[snipped]

Thanks for reformulating the example, it makes it a lot easier to follow.

Problem is that "Set getLocDeptsByLocation( int locationId )" method also
tries
to resolve all the references in LocDept. Since LocDept has 2 references
Location and Department so it retrieves them as well.

If I'm following this correctly then you have a problem here even if your code
didn't go into a loop. It sounds as if loading one Departement would cause all
the corresponding Locations to be loaded, which in turn would cause more
Deparements to be loaded, and so more Locations, etc.... In the end you'd be
lucky if you hadn't copied the entire contents of the database (or those three
tables anyway) into memory.

My first thought would be to make the cross-referencing lazy, so that when you
load a Departement it doesn't attempt to find the list of LocDepts at that
time, but only when your code asked for it. Similarly for Locations. In
turn, the LocDept wouldn't automatically load either the Location or the
Departement until it was actually needed (actually that might be
over-optimisation unless it is quite common for you to use a LocDept without
necessarily accessing its Location or Departement).

That would both avoid the loop, and avoid loading more data from the DB than
you actually need.

There are other ways of approaching this sort of problem -- Andrea's suggestion
is a good one. Which is better depends on your application.

-- chris
 
A

Andrew Thompson

Don't be silly, Andrew, this is a code structuring problem, not a bug needing
an SCCE

(S)SCCE. A *Short*, Self Contained, Compilable Example.
..for demonstration.

Oh, good point, I was fooled by the OP reposting the same
(seemingly) example first posted, in response to Oliver's
request for an SSCCE.

--
Andrew Thompson
physci.org 1point1c.org javasaver.com lensescapes.com athompson.info
"..I pick up all the pieces and make an island. Might even raise just a
little sand"
Jimi Hendrix 'Voodoo Chile (Slight Return)'
 
R

Rizwan

My first thought would be to make the cross-referencing lazy, so that when
you
load a Departement it doesn't attempt to find the list of LocDepts at that
time, but only when your code asked for it. Similarly for Locations. In
turn, the LocDept wouldn't automatically load either the Location or the
Departement until it was actually needed (actually that might be
over-optimisation unless it is quite common for you to use a LocDept
without
necessarily accessing its Location or Departement).

That would both avoid the loop, and avoid loading more data from the DB
than
you actually need.

Thanks Chris. You have correctly figured out my problem. And your solution
"lazy cross-referencing" is right on target. Question is how to do it?

For example:

public class Location {
private int locationId;
private Set locDepts = new HashSet(); // of type LocDept
...
public int getLocationId() { return locationId; }
public void setLocationId( int locationId ) { this.locationId =
locationId; }
public Set getLocDepts() { return locDepts; }
public void setLocDepts( Set locDepts ) { this.locDepts = locDepts; }
...
}

I have these DAO methods:
public Location getLocation( int locationId ); // in
LocationDAO.java
public Department getDepartment( int departmentId ); // in
DepartmentDAO.java
public Set getLocDeptsByLocation( int locationId ); // in
LocDeptDAO.java

Then this is my test code:
DAOFactory daoFactory = DAOFactory.getDAOFactory( );
LocationDAO locationDAO = daoFactory.getLocationDAO();
Location location = locationDAO.getLocation( 1 );

Now this location object does not have its attribute "locDepts" populated
yet as its lazy cross-referencing. Only when I call
Set thisLocationLocDepts = location.getLocDepts();
then it should do three things:
1) retrieve LocDepts data in a Set
2) set this Set to location object's "locDepts" attribute
3) return the Set

Here i have some questions:

* For Step 1) it appears to me that getLocDepts() method should call "public
Set getLocDeptsByLocation( int locationId );" method of LocDeptDAO.java. But
the getLocDepts() method only returns locDepts as per java-beans style. So
how can i do that?

* Step 1) should only happen when location object has been retrieved. If its
an insert like this : Location location = new Location(); then if i call
Set thisLocationLocDepts = location.getLocDepts();
then it should do only one thing:
1) return the Set

I am pretty sure that there is a solution without compromising java-beans
style of Location class. But dont know how. Please response.

Thanks

Rizwan
 
A

Andrew Thompson

Andrew said:
(S)SCCE. A *Short*, Self Contained, Compilable Example.

I future I shall refer to them as "[SC]+E" ...

Sure, but, ..it seems like more effort (8 keystrokes, by
my count). Why not go simpler, to S+C+E (6) or SCE (4)?
 
C

Chris Uppal

Rizwan said:
public class Location {
private int locationId;
private Set locDepts = new HashSet(); // of type LocDept
...
public int getLocationId() { return locationId; }
public void setLocationId( int locationId ) { this.locationId =
locationId; }
public Set getLocDepts() { return locDepts; }
public void setLocDepts( Set locDepts ) { this.locDepts = locDepts; }
...
}

I'd say that your problem here is that you are thinking of your getXxxx methods
(getLocDepts() and so on) as actual "getters" -- i.e. that the /purpose/ of
those methods is to retrieve the value of a field. I assume that's what you
mean by "java bean style".

I don't know how much it would affect your overall application, but what /I/
would do is change to a proper OO style, where the purpose of the method is to
tell you something about the object in question, not merely to be a way of
getting the current value of a field. When you think of it that way, it makes
perfect sense for getLocDepts() (for example) to check to see if the field
locDepts is null, and if it is to use your DAO object to fill in the required
value before returning (obviously you should initialise the locDepts field to
null, rather than a to Set).

I'm sorry if this hasn't answered your question -- after all you asked how to
do it in "java beans style", and I'm suggesting that you do it in OO style
instead. But I think it's important to realise that the very /concept/ of
getter and setter methods is opposed to good OO programming (or, indeed, to
good programming). Blind use of getter/setter pairs is often a symptom of poor
design, and is always prone to lead you into overcomplicated code as you
attempt to compensate for the excessively low-level API to your objects. I
think this case is an example of that in practise.

-- chris
 
O

Oliver Wong

Chris Uppal said:
But I think it's important to realise that the very /concept/ of
getter and setter methods is opposed to good OO programming (or, indeed,
to
good programming).

Just wanted to point out to those who may not be familiar with the
debate around getters and setters that the above statement is a bit
controversial and not widely agreed upon one way or the other. I.e. some
people think getters and setters are "good" while others think they are
"bad" (oversimplifying here).
Blind use of getter/setter pairs is often a symptom of poor
design, and is always prone to lead you into overcomplicated code as you
attempt to compensate for the excessively low-level API to your objects.

This, I agree with. Blind use of ANYTHING is bad. getter/setters are a
tool, and in the right situation, can be very useful.

- Oliver
 
C

Chris Uppal

Oliver said:
[me:]
But I think it's important to realise that the very /concept/ of
getter and setter methods is opposed to good OO programming[...]
Just wanted to point out to those who may not be familiar with the
debate around getters and setters that the above statement is a bit
controversial and not widely agreed upon one way or the other. I.e. some
people think getters and setters are "good" while others think they are
"bad" (oversimplifying here).

I think you need to be a bit careful when you talk of "the debate around
getters and setters". In fact there are /three/ debates which are not, IMO,
particularly strongly related but which tend to get lumped together
confusingly.

The first is about whether objects should expose their instance fields
directly. Conventional wisdom says no, and since I'm in complete agreement
with conventional wisdom in this case, as are the overwhelming majority of
other programmers, I consider this to question be more-or-less settled.

The second is about whether an object should access /its own/ state via
accessor methods, or whether it should simply read/write the fields directly.
This debate is not particularly interesting to me, here, since it doesn't
involve questions of application structure. (In fact, a lot of people seem to
think that it's "just obvious" that good code will use accessor methods in
place of direct access. I have never seen any justification for this -- not
even a "justification" that made some sense but was ultimately flawed. As far
as I can see the people who hold this view are just confused and/or
regurgitating "commandments" from teachers who were themselves confused[*].)

The third debate is the one I'm more interested in -- my view (which I agree is
not shared by everyone) is that the concept of accessors is incompatible with
sound OO design. The methods that an object has should be determined by the
role (or roles) it has to play -- by what information it is supposed to be able
to provide, and what information it needs in order to do its job. That has
nothing at all to do with instance fields. Yet the "accessor" concept is bound
tightly to instance fields (to the extent, for instance, that the names of
instance fields are reflected in the names of the methods[**] !). The habit of
thinking in terms of "accessors" leads to code with poor division of
responsibility, and is -- I strongly suspect -- the cause Rizwan's difficulty
seeing how to implement lazy population of his objects' states.

-- chris

(

[*] Compare the "no early return" credo, for a similar case of hand-me-down
nonsense.

[**] Here's an extreme example of this kind of thinking. I like the convention
of prefixing instance field names with "m_" and said so in this NG once. One
person objected to the idea (well, several people objected to the idea...) on
the grounds that s/he didn't want to use method names like "getM_Xxx()", which
accessor methods would "of course" have....

)
 
O

Oliver Wong

Chris Uppal said:
I think you need to be a bit careful when you talk of "the debate around
getters and setters". In fact there are /three/ debates which are not,
IMO,
particularly strongly related but which tend to get lumped together
confusingly.

The first is about whether objects should expose their instance fields
directly. Conventional wisdom says no, and since I'm in complete
agreement
with conventional wisdom in this case, as are the overwhelming majority of
other programmers, I consider this to question be more-or-less settled.

When you said accessors went against the good OO design, I thought this
is what you meant. I'm with what you call the conventional wisdom, but I
know a few programmers whom I respect a great deal and who feel that it very
acceptable to expose instance fields. We agreed to disagree on that issue.

The second is about whether an object should access /its own/ state via
accessor methods, or whether it should simply read/write the fields
directly.
This debate is not particularly interesting to me, here, since it doesn't
involve questions of application structure. (In fact, a lot of people
seem to
think that it's "just obvious" that good code will use accessor methods in
place of direct access. I have never seen any justification for this --
not
even a "justification" that made some sense but was ultimately flawed. As
far
as I can see the people who hold this view are just confused and/or
regurgitating "commandments" from teachers who were themselves
confused[*].)

The reason for using "getters" in the first place, I think, is to not
make it obvious what properties of the object come directly from fields, and
which are a result of more complex computations. Sometimes this will even
change! As a simple example, you might have a "Temperature" class which
internally stores the temperature as celcius, but provide getters which
allow you to view the temperature either in celcius of fahrenheit. Later on,
you may change your mind and what to store the data internally as
fahrenheit. Or perhaps you might want to store it internally as kelvin.
Ideally, if you've used getters instead of direct-field access, none of the
client code using your Temperature class has to change as a result of this.

Now if within the code for the Temperature class itself, you might have
a method which takes the current pressure as an argument and returns whether
water would be in a liquid, solid or gaseous state at this temperature and
pressure combination. If you directly accessed the fields, when you decide
to make the change from celcius to kelvin, you'd have to change this code as
well. If you use instead you got the temperature via one of the getter
methods (e.g. getCelcius()), then this code would not need to change.

So I try to use accessor methods instead of direct access, but I admit
to occasionally getting lazy and just doing direct access.
The third debate is the one I'm more interested in -- my view (which I
agree is
not shared by everyone) is that the concept of accessors is incompatible
with
sound OO design. The methods that an object has should be determined by
the
role (or roles) it has to play -- by what information it is supposed to be
able
to provide, and what information it needs in order to do its job. That
has
nothing at all to do with instance fields. Yet the "accessor" concept is
bound
tightly to instance fields (to the extent, for instance, that the names of
instance fields are reflected in the names of the methods[**] !). The
habit of
thinking in terms of "accessors" leads to code with poor division of
responsibility, and is -- I strongly suspect -- the cause Rizwan's
difficulty
seeing how to implement lazy population of his objects' states.
[*] Compare the "no early return" credo, for a similar case of
hand-me-down
nonsense.

[**] Here's an extreme example of this kind of thinking. I like the
convention
of prefixing instance field names with "m_" and said so in this NG once.
One
person objected to the idea (well, several people objected to the idea...)
on
the grounds that s/he didn't want to use method names like "getM_Xxx()",
which
accessor methods would "of course" have....

I think the issue then is not that accessors are "bad", but that they
are misunderstood or misused. I agree with you that methods should either do
something, or give information. And I agree that there's no reason why a
methods which give information needs to have a corresponding instance field.
But I would still call such a method an "accessor" or a "getter". Just that
instead of accessing information stored in one particular field, it's
accessing information from elsewhere (perhaps distributed across multiple
fields via some formula).

- Oliver
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top