These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 9 posts ] 
Author Message
 Post subject: How to map a <map> where element is a <set> of e
PostPosted: Tue Nov 13, 2007 6:56 pm 
Newbie

Joined: Wed Jul 27, 2005 3:44 pm
Posts: 12
Location: Los Angeles, CA
Need help with Hibernate? Read this first:
http://www.hibernate.org/ForumMailingli ... AskForHelp

Hibernate version: 3.0.5

Mapping documents:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.business.sem" default-cascade="save-update" default-lazy="true">
<class name="VendorAccount" lazy="true" select-before-update="false" table="VendorAccount">
<meta attribute="implements">com.business.sem.IEntityState</meta>
<meta attribute="implements">com.business.sem.ISecurity</meta>
<id name="id" type="java.lang.Long" column="id">
<meta attribute="use-in-tostring">true</meta>
<generator class="identity" />
</id>
<property name="name" column="name" length="50" type="java.lang.String" not-null="true">
<meta attribute="use-in-tostring">true</meta>
<meta attribute="field-description">Name of the account</meta>
</property>
<one-to-one name="settings" class="VendorAccountSettings"
cascade="save-update"
constrained="false"
outer-join="true"
lazy="false"
fetch="join" />

<map name="biddingSchedule" outer-join="true" fetch="select" table="BiddingSchedule" lazy="true">
<key column="accountId" not-null="true" unique="false" />
<map-key-many-to-many class="com.business.sem.DistributionType" column="distributionType" />
<one-to-many class="BiddingSchedule" />
</map>

<map name="biddingExceptions" inverse="true" outer-join="true" fetch="select" order-by="exceptionDate desc" table="BiddingException" lazy="true">
<key column="accountId" not-null="true" unique="false" />
<map-key-many-to-many class="com.business.sem.DistributionType" column="distributionType" />
<one-to-many class="BiddingException" />
</map>

<many-to-one name="type" class="AccountType" column="accountType" fetch="select" cascade="none" not-null="true">
<meta attribute="field-description">Type of this VendorAccount</meta>
</many-to-one>

<property name="lastUpdate" column="lastUpdate" type="java.sql.Timestamp" not-null="false" update="false" insert="false" />

<many-to-one name="status" class="Status" column="status" fetch="select" cascade="none" not-null="true">
<meta attribute="field-description">Status of this VendorAccount</meta>
</many-to-one>
</class>
</hibernate-mapping>

Name and version of the database you are using:
SQLServer 2000

BiddingException table is (pseudo-sql):
id INT PRIMARY KEY
accountId BIGINT FOREIGN KEY FOR VendorAccount.id
distributionType CHAR(1) FOREIGN KEY FOR DistributionType.code
exceptionDate DATETIME;

As you can see, VendorAccount can have multiple BiddingExceptions (1:M).
How can I map this relationship? I would like to be able to use it like this:

Code:
Set<java.sql.Date> dateSet = vendorAccount.getBiddingSchedule().get (SEARCH_MARKETING_TYPE)


The <map> definition in bold above maps just single date per each value of <map-key-many-to-many> and the spec doesn't allow to specify a <set> inside the <map> definition.

Is there a better way to map it? I think I could do it using subclasses: then I could use map key as a discriminator and get all ContentBiddingExceptions and SearchMarketingBiddingExceptions, but I'd prefer to just have a map keyed by DistributionType and containing Lists of dates, or list of BiddingExceptions.

_________________
Maxim Senin
Custom Software Development for the Enterprise
http://www.supremistic.com/


Top
 Profile  
 
 Post subject: I have the same question
PostPosted: Tue Nov 13, 2007 9:52 pm 
Newbie

Joined: Tue Nov 13, 2007 7:08 pm
Posts: 10
Location: Australia
Hi,

Hibernate version: 3.2.5

I have read the Hibernate Reference Documentation and have created the following isolated case. I haven't been able to work out how hibernate can model it... Please help.

Data Model

The following class diagram shows the relationship between an Event and a Person. An Event may have many participants (of class Person) of various types, for example a party may have many guests and a few VIP participants. Conversely, a person may be participating in many events, for example I may be a guest at a dinner and a VIP at the after party.

Image

Where type could be "VIP", "Guest", "Volunteer", etc.

Database Schema

We have event and person table, we also have a join table call participant. The participant table also has a type column to store association attribute, hence a surrogate id is needed.

Code:
TABLE event ( event_id BIGINT NOT NULL PRIMARY KEY, ... )
TABLE person ( person_id BIGINT NOT NULL PRIMARY KEY, ... )
TABLE participant ( participant_id BIGINT NOT NULL PRIMARY KEY, event_id BIGINT NOT NULL FOREIGN KEY event, person_id BIGINT NOT NULL FOREIGN KEY person, type VARCHAR(...) )


POJO Implementation

What Hibernate mapping (if any) would provide the following?

Code:
Event event = ...;
Map participants = event.getParticipants();
Set guests = participants.get("guest");
Person guest = guests.get(0);


Alternatives

Participant could be modeled as a class or component and participants could be mapped as a set with field access, while the Map returned by Event.getParticipants is created programmatically using filters.

Any comments?


Last edited by corin on Wed Nov 14, 2007 8:09 am, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Tue Nov 13, 2007 10:44 pm 
Newbie

Joined: Wed Jul 27, 2005 3:44 pm
Posts: 12
Location: Los Angeles, CA
My short-term solution is ugly but it works. I'd like to solicit a better idea.

For now I just mapped the relationship as a <set> and use Criteria to get the subset by the key that I need.

Filters are nice too, but you have to enable/disable them.

_________________
Maxim Senin
Custom Software Development for the Enterprise
http://www.supremistic.com/


Top
 Profile  
 
 Post subject: The beautiful solution
PostPosted: Tue Nov 13, 2007 11:25 pm 
Newbie

Joined: Tue Nov 13, 2007 7:08 pm
Posts: 10
Location: Australia
msenin wrote:
My short-term solution is ugly but it works. I'd like to solicit a better idea.


I guess, the ideal solution would be a hibernate mapping. My first attempt was to use map-key-many-to-many (like yourself), only to discover that the index column had to be unique (ie. the primary key of the join table is a combination of the two foreign keys and the index column). This (to me) seems like a artificial constraint, I see no problem with the table structure that I proposed that maps to a Map of Sets.

I am only a newbie to hibernate and would love someone to say (with authority) that a the table structure I proposed cannot be mapped to a 'Map of Sets' using a hibernate mapping. And that, a 'Map of Sets' can't be mapped at all (regardless of table schema) using a hibernate mapping. I would then ask 'why not' and 'please add it'.

I am perfectly happy to accept that there is no hibernate mapping and that a programmatic approach is needed. (The argument could be made that a 'Map of Sets' is ugly, but that would depend on your application's needs, I guess.) There is nothing inherently ugly about the programmatic approach, it just takes more effort, that's all. Also, (as a newbie) I don't know what is the best or most efficient way to split the Set into many Sets... I haven't used Criteria or Filters. I'll definitely look at them both (one day, when I have time ;)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 14, 2007 12:54 am 
Newbie

Joined: Wed Jul 27, 2005 3:44 pm
Posts: 12
Location: Los Angeles, CA
Can you map your set elements using <composite-element>?

As you said, the biggest problem is that <map-key-many-to-many> and <key> combination have to be unique...

_________________
Maxim Senin
Custom Software Development for the Enterprise
http://www.supremistic.com/


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 14, 2007 4:45 am 
Newbie

Joined: Tue Nov 13, 2007 7:08 pm
Posts: 10
Location: Australia
msenin wrote:
Can you map your set elements using <composite-element>?


Yes, regardless of whether the element is a component or an entity, I get a set containing Participants when I actually want a set containing Persons.

On further reflection, I don't think that filters or criteria can achieve the Map of Sets of Persons. Any filter or criteria would return a collection of Participants. What did your Criteria expression look like? Is distributionType and date encapsulated in a BiddingException? Also, I think I have posed a different problem (your association is one-to-many not many-to-many), right?


Top
 Profile  
 
 Post subject: My compromise
PostPosted: Wed Nov 14, 2007 6:17 am 
Newbie

Joined: Tue Nov 13, 2007 7:08 pm
Posts: 10
Location: Australia
Hi,

I have made a small compromise: fortunately, I know the participant types at deployment time. Hence, I can use native sql in the hibernate mapping to create an idbag for each type and put each bag into a Map programmatically at runtime. The only drawback is that I must have that knowledge at deployment time (and my mapping could become very large and difficult to maintain).

Hibernate Mapping

Example:
Code:
        <idbag name="vipParticipants" table="participant" access="field"
                where="type = 'VIP'">
            <collection-id column="participant_id" type="long">
                <generator ... />
            </collection-id>
            <key column="event_id"/>
            <many-to-many column="person_id" class="events.Person"/>
            <sql-insert>INSERT INTO participant (type, event_id, participant_id, person_id) VALUES ('VIP', ?, ?, ?)</sql-insert>
        </idbag>


I have added:
  • the where attribute to the idbag element; and
  • the sql-insert element (see the Hibernate Reference Documentation before using this!).


Note that the sql-delete and sql-delete-all elements aren't needed since the participant_id is used. And the sql-update element isn't needed since an updated is never used/needed (I think/hope).


Last edited by corin on Wed Nov 14, 2007 8:39 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 14, 2007 1:27 pm 
Newbie

Joined: Wed Jul 27, 2005 3:44 pm
Posts: 12
Location: Los Angeles, CA
You are right, I've 1:M. For each VendorAccount I have a list of BiddingExceptions.
I could use <idbag> and an <element> containing just the exceptionDate to model my BiddingException. But it doesn't seem to solve the problem of uniqueness of accountId+distributionType.
I think your latest solution is no different then defining two sets mapped into same table. Since you basically limit yourself to the known map keys, it's not different then defining two sets, such as VendorAccount.searchMarketingExceptions and VendorAccount.contentMatchExceptions, or using concrete subclasses in a single collection and using map-key as a discriminator.

Code:
VendorAccount:
  id
  name
  ...

BiddingException:
  id
  accountId
  distributionType
  exceptionDate

DistributionType:
  code
  description

_________________
Maxim Senin
Custom Software Development for the Enterprise
http://www.supremistic.com/


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 14, 2007 10:34 pm 
Newbie

Joined: Tue Nov 13, 2007 7:08 pm
Posts: 10
Location: Australia
msenin wrote:
I think your latest solution is no different then defining two sets mapped into same table. Since you basically limit yourself to the known map keys, it's not different then defining two sets, such as VendorAccount.searchMarketingExceptions and VendorAccount.contentMatchExceptions...


It is precisely that. Note that searchMarketingExceptions and contentMatchExceptions are not necessarily mutually exclusive or equivalent. I think I wasn't clear on that before; a Person may be a 'VIP' and a 'volunteer' at the same event.

msenin wrote:
... or using concrete subclasses in a single collection and using map-key as a discriminator.


It's different to this because the concrete classes would have to be subclasses of Participant not Person.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 9 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.