• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Subset of relationship
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Subset of relationship


  • Subject: Re: Subset of relationship
  • From: Ken Anderson <email@hidden>
  • Date: Wed, 10 Aug 2005 09:08:29 -0400

Emerson,

Yes, as you have quite properly ascertained, this is a very age-old problem in object modeling.

To me, the perfect example of this, illustrated once by a NeXT trainer named Tom Affinito (long time ago!) is the desire to model cars. If you tried to use subclassing for modeling different engines, wheels, bodies, transmissions, etc., you'd end up with something completely unmaintainable. His view was, this is a job for 'componentization' rather then a hierarchy. So, your idea of adding different objects (components) underneath the higher level controlling objects is an excellent one.

I usually try to approach these types of problems questioning whether some behaviors can be completely separated from others, but different parts of the structure would be interested in the same behavior. These are usually excellent candidates for components rather than hierarchies.

Ken

On Aug 10, 2005, at 7:43 AM, Emerson wrote:

Thanks to all those who helped,

I see the way to go is inheritance. I had already digged into it in the
manual, but as it strongly suggests, I tried my best to avoid it in the
first place. Mostly because the manual itself is quite clear when
talking about Using EOModeler to build a model with inheritance, but
almost nothing is said on how to properly make use of inheritance in
code. Probably because that's more a Java issue, but I guess beginners
lack the proper knowledge to figure that out by themselves.


Anyway, that leads me to another issue.

Supposing you had another brand of specialization under Message, say
TextMessage and HTMLMessage, just to go on with the same example. An
HTML message could be related to some records from an Image entity.

For inclusion, if I chose the brand Draft/Message to create a new EO, I
would lose the opportunity to insert images in an HTML message. If I
chose instead the brand TextMessage/HTMLMessage to create a new EO,
there would be no problem, since I would still have a property "draft"
where I could set the corresponding datum.


However, if I tried to retrieve "all the HTML messages sent", I would go
back to the initial problem, which tells me I should have an
specialization brand also under HTML Message. This seems to be a little
bit clumsy, since I would possibly be defining Draft/Message three
times, one for Message, one for TextMessage and one for HTMLMessage,
providing that I needed to fetch "all the HTML messages sent", "all the
text messages sent", "all messages sent", "all text drafts", "all HTML
drafts" and "all drafts", for instance.


If I had three specialization brands under Message, the problem would be
even harder.


Besides, if I had a hierarchy like:
                Person -------------------------
                |                               |
       Native ----- Foreigner       Customer ------ Employee

each specialization of each brand would possibly have its own properties
and relationships. In that case, creating a person as a Customer would
just make his or her unable to be classified as Citizen or Foreigner.


This looks like a feature of the OO paradigm, at least the way it is
implemented in Java, instead of an issue with EOF.

A possibility I see is: create an instance under Customer/Employee. As
soon as you have finished setting the desired properties/relationships
available under that specialization, set a flag to determine if the
brand new EO is either a Native or Foreigner. Next, fetch that object
from the Native entity, if it is a native, or otherwise from the
Foreigner entity. After that, fill in the remaining blanks. To fetch the
exact object, use a kind of identification which is known to be unique
and a corresponding fetch specification.


Would that be ok? Is it a good alternative? Are there better approaches?
Is it possible to fault the exact object from one entity onto another
instead of doing a fetch?


Replicating inheritance nodes does not seem to be elegant.


Em Ter, 2005-08-09 às 19:49 -0400, Jerry W. Walker escreveu:

I think Ken's advice is excellent. I will simply augment it with some
code in case you're having trouble getting started with that.

On Aug 9, 2005, at 5:15 PM, Ken Anderson wrote:


Emerson,

You're not doing anything really wrong - it just takes a little
time to understand the tool.

The way to choose the approach to take is often a function of the
number of records you expect to be processing and the split between
the 2 different groups.  I responded to each of your ideas below.

Ken

On Aug 9, 2005, at 4:44 PM, Emerson wrote:



Hello friends,

I have a very basic question, mainly because I've just recently
started
developing in WO. Although I have some ideas, I'd like to get some
feedback in order to use best practices right from the beginning.

Consider a model where you have a number of entities. In that model,
User records users and Message records messages sent and drafts
saved by
users. I decided not to split messages sent and drafts saved in two
different entities because several properties and relationships would
have been duplicated; moreover, since a draft can become a
message, it
sounded inefficient to me having to create a new message and
literally
copy each and every property/relationship whenever a draft was
sent. It
sounds like just a state change.


Nothing new so far.

It happens that I would like to browse either all messages sent or
all
drafts saved by a user, but not both at the some time. EOF gives me a
NSArray of Messages, containing both messages sent and drafts saved,
resulting from the relationship with the entity Message.


What's the most recommended way of getting a NSArray with only the
drafts saved or messages sent?
1. using an in-memory operation with java.util.Enumerator to split
messages sent and drafts saved (by looking at the value of a "state"
property); this approach sounds inefficient, since all messages are
fetched and comparisons are made in memory; databases are probably
better at that job. By the way, I feel this alternative should use
something like NSKeyValeCoding and NSKeyValueCodingAdditions
instead of
enum, but I just can't figure out how.




This is sometimes a good approach if you want to keep your eomodel simple and you don't think you'll have very many objects. It also only works well if there will be a reasonably equal number of both so that one side doesn't become inefficient (like looking for 1 Draft inside a box of 4000 Messages).


If you go with an in memory array, I would suggest using EOQualifier's static methods, either

     public static NSArray filteredArrayWithQualifier(NSArray array,
EOQualifier qualifier)

or

      public static void filterArrayWithQualifier(NSMutableArray
array, EOQualifier qualifier)

The former applies a qualifier to a static array (say, your Message
array) and returns a new array containing the subset of qualified
values (say, your drafts). The latter applies a qualifier to a
mutable array and reduces that array to a qualified subset.

So presuming you have some state variable in Message, such as
isDraft, you might write it as:

   EOQualifier getDraftsQualifier =
EOQualifier.qualifierWithQualifierFormat("isDraft = 'Y'", null);
   NSArray theDrafts = EOQualifier.filteredArrayWithQualifier
(aUser.messages(), getDraftsQualifier);

Alternatively, you could write it as:

EOQualifier getDraftsQualifier =
EOQualifier.qualifierWithQualifierFormat("isDraft = 'Y'", null);
NSMutableArray theDrafts = aUser.messages().mutableClone();
EOQualifier.filterArrayWithQualifier(theDrafts, getDraftsQualifier);


I would prefer the former unless there were a good reason for having
the mutable array.



2. creating a fetch specification in the entity Message which returns
all drafts for a given userid. In the class User, a method named
draftsFS could be defined so that it creates a new fetch
specification
by assigning the userid obtained with EOUtilities to the raw fetch
specification defined in the entity Message; the application would
be in
charge of doing the fetch. This approach just "forgets" the default
relationship.




I try to avoid using this approach, since it takes you out of the EOF loop, and you lose some of EOF's features, especially things like batch faulting. It does, however, have its place, especially if the query is more complex than what you're doing.


I agree with Ken in generally avoiding this approach, but more so because it seems to be the product of "result sets" thinking. I think a lot about database artifacts like userId when creating my EOModel, but try my best to forget about them later in the depths of my OO code. I do my best to avoid making them class properties.

However, a fetch specification could be created to obtain a given
user's drafts. For a fetch this simple, however, I would tend to one
of the EOUtilities shortcuts, such as objectsMatchingValues():

   EOEditingContext ec = xx; // where xx = <some editing context,
such as session().defaultEditingContext if in a WOComponent>
   NSDictionary keyValueDict = new NSDictionary(new Object[] {myUser,
"Y"}, new Object[] {"user", "isDraft"}) ;
   NSArray usersDrafts = EOUtilities.objectsMatchingValues(ec,
"Message", keyValueDict);


3. the model should be redesigned so Messages and Drafts are set
apart.



This is the one I'd choose for your particular situation, but not in the way you think. I would have an entity Message, with 2 sub- entities - Draft and Sent (or something like that). If you had a draft flag, I would put restricting qualifiers on the entity like this:

Message    draft = NULL
Draft            draft = 'Y'
Sent            draft = 'N'

I would make sure that draft is never NULL, so Message never gets
instantiated (it should also be marked as an Abstract Entity).

You can now have 2 relationships, each pointing to the proper
entity, and you will only get the right results for each one.  If a
message goes from being a draft to real, updating the Sent property
will do the right thing next time you fetch.  You can implement
most of your code in the Message class so that both entities share
most of the code (only override what you need to in Draft & Sent).


EOF gives you three ways to map such subclasses onto the tables of an RDB:

   * vertical inheritance - a table for each of Message, Draft and
Sent with only the data in Draft and Sent that differentiate them.

   * horizontal inheritance - a table only for Draft and for Sent in
which the Message(s) are partitioned across these two tables.

   * single table inheritance - a table for Message in which the rows
can be distinguished by a state variable such as Ken described.

Now that you have the buzzwords for these, it's easy enough to look
them up in the EOF documentation. I think your problem argues
strongly for single table inheritance, since the only difference
between the two subclasses is the value of the state variable.


Since I'm having problems with such a basic issue, I know I must be
doing something really wrong and that's why I decided to request your
opinions.



Again, I agree with Ken. WO and EOF provide rich language with a cornucopia of "phrases" to say the same thing. It takes a while to figure out the appropriate idioms.

Best regards,
Jerry

--
__ Jerry W. Walker, Partner
     C o d e F a b, LLC - "High Performance Industrial Strength
Internet Enabled Systems"
     email@hidden
     212 465 8484 X-102  office
     212 465 9178        fax





_______________________________________________
Do not post admin requests to the list. They will be ignored.
Webobjects-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
40anderhome.com


This email sent to email@hidden


_______________________________________________ Do not post admin requests to the list. They will be ignored. Webobjects-dev mailing list (email@hidden) Help/Unsubscribe/Update your Subscription: This email sent to email@hidden
References: 
 >Subset of relationship (From: Emerson <email@hidden>)
 >Re: Subset of relationship (From: Ken Anderson <email@hidden>)
 >Re: Subset of relationship (From: "Jerry W. Walker" <email@hidden>)
 >Re: Subset of relationship (From: Emerson <email@hidden>)

  • Prev by Date: Re: Subset of relationship
  • Next by Date: Re: WebObjects with JBoss deployment
  • Previous by thread: Re: Subset of relationship
  • Next by thread: Re: Subset of relationship
  • Index(es):
    • Date
    • Thread