-->
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.  [ 6 posts ] 
Author Message
 Post subject: Dictionary of components where key is a property of cmpnt?
PostPosted: Mon Mar 26, 2007 5:15 am 
Newbie

Joined: Mon Mar 26, 2007 3:59 am
Posts: 4
Location: Estonia
Hibernate version: 1.2.0.CR1

Is it possible to map a generic dictionary of value objects (composite-elements) where the key is a property from the composite-element?

This is the mapping for the dictionary:
Code:
   <map name="Values" table="CurrencyPrice" cascade="all-delete-orphan" access="nosetter.camelcase-underscore">
      <key column="PriceId" />

      <index-many-to-many column="CurrencyId" class="MyApplication.Domain.Currency, MyApplication.Domain" />

      <composite-element class="MyApplication.Domain.Money, MyApplication.Domain">
         <property
            name="Amount"
            column="Value"
            type="Decimal"
            access="nosetter.camelcase-underscore" />
         <many-to-one
            name="Currency"
            column="CurrencyId"
            class="MyApplication.Domain.Currency, MyApplication.Domain"
            access="nosetter.camelcase-underscore"
            not-null="true" />
      </composite-element>
   </map>


As you can see, I'm using the column CurrencyId twice - as the dictionary's key and as a property of the composite-element "Money".
I get the following NHibernate.MappingException when building the SessionFactory:

Quote:
Repeated column in mapping for collection: MyApplication.Domain.Price.Values column: CurrencyId

Type: NHibernate.MappingException
Source: NHibernate
TargetSite: Void CheckColumnDuplication(Iesi.Collections.ISet, System.Collections.ICollection)
HelpLink: null
Stack: at NHibernate.Persister.Collection.AbstractCollectionPersister.CheckColumnDuplication(ISet distinctColumns, ICollection columns)
...


Mapping documents:

Price.hbm.xml
Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-cascade="save-update">
   <class name="MyApplication.Domain.Price, MyApplication.Domain" table="Price" lazy="true">
      <id name="Id" column="Id" type="Int32" unsaved-value="0" access="nosetter.camelcase-underscore">
         <generator class="identity" />
      </id>

      <map name="Values" table="CurrencyPrice" cascade="all-delete-orphan" access="nosetter.camelcase-underscore">
         <key column="PriceId" />

         <index-many-to-many column="CurrencyId" class="MyApplication.Domain.Currency, MyApplication.Domain" />

         <composite-element class="MyApplication.Domain.Money, MyApplication.Domain">
            <property
               name="Amount"
               column="Value"
               type="Decimal"
               access="nosetter.camelcase-underscore" />
            <many-to-one
               name="Currency"
               column="CurrencyId"
               class="MyApplication.Domain.Currency, MyApplication.Domain"
               access="nosetter.camelcase-underscore"
               not-null="true" />
         </composite-element>
      </map>

      <!-- SNIP -->
   </class>
</hibernate-mapping>


Currency.hbm.xml
Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-cascade="save-update">
   <class name="MyApplication.Domain.Currency, MyApplication.Domain" table="Currency" lazy="true">
      <id name="Id" column="Id" type="Int32" unsaved-value="0" access="nosetter.camelcase-underscore">
         <generator class="identity" />
      </id>

      <property
         name="Code"
         column="CurrencyCode"
         type="String"
         access="nosetter.camelcase-underscore"
         not-null="true" />

      <!-- SNIP -->
   </class>
</hibernate-mapping>


Domain objects:

Value object "Money":
Code:
struct Money {
   decimal Amount { get; }
   Currency Currency { get; }
}


Entity "Currency":
Code:
class Currency {
   int Id { get; }
   string Code { get; } // "EUR", "USD" etc.
   // ...
}


The Price object holds prices for a product in different currencies. To make it easy to get the price of a product in a given currency, I would like to have a dictionary of the

prices:

Code:
class Price {
   Dictionary<Currency, Money> Values { get; }
}


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 26, 2007 9:20 am 
Newbie

Joined: Mon Mar 26, 2007 3:59 am
Posts: 4
Location: Estonia
I've now circumvented the problem by mapping a decimal (as an element) instead of the Money as a composite-element, so now I have an IDictionary<Currency, decimal> instead of IDictionary<Currency, Money>:

Code:
class Price {
   IDictionary<Currency, decimal> Values { get; }

   public virtual Money GetValue(Currency currency) {
      return new Money(currency, Values[currency]);
   }
}


This is definitely not the way I want to keep it, but it'll have to do for now.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 28, 2007 5:51 am 
Newbie

Joined: Tue Mar 20, 2007 11:48 am
Posts: 11
I'm having the same problem, searched on the net but didn't find any solution, any help would be appreciated...


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 29, 2007 3:55 am 
Senior
Senior

Joined: Mon Aug 21, 2006 9:18 am
Posts: 179
The cause for this is simple...you can't have two columns with the same name in a table. So you need to change one of the 'column name' attributes to a different value. For example, I use the suff '_idx' for column names that are the indices for lists,etc...So it would become this...
Code:
<map name="Values" table="CurrencyPrice" cascade="all-delete-orphan" access="nosetter.camelcase-underscore">
      <key column="PriceId" />

      <index-many-to-many column="CurrencyId_idx" class="MyApplication.Domain.Currency, MyApplication.Domain" />

      <composite-element class="MyApplication.Domain.Money, MyApplication.Domain">
         <property
            name="Amount"
            column="Value"
            type="Decimal"
            access="nosetter.camelcase-underscore" />
         <many-to-one
            name="Currency"
            column="CurrencyId"
            class="MyApplication.Domain.Currency, MyApplication.Domain"
            access="nosetter.camelcase-underscore"
            not-null="true" />
      </composite-element>
   </map>


Notice I change the following element with my _idx suffix:
Code:
<index-many-to-many column="CurrencyId_idx" class="MyApplication.Domain.Currency, MyApplication.Domain" />


Hope this helps...

_________________
If this helped...please remember to rate it!


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 29, 2007 10:55 am 
Newbie

Joined: Mon Mar 26, 2007 3:59 am
Posts: 4
Location: Estonia
thanks, it's working now! It also seems that cascade="all-delete-orphan" does not work on a composite-element collection. I get a MappingException with the message "collection was not an association" when trying to save the owner of the collection (i.e. the price).


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 30, 2007 12:55 am 
Senior
Senior

Joined: Mon Aug 21, 2006 9:18 am
Posts: 179
Glad it worked. You are correct about the all-delete-orphan on a component....I've gotten bit by that one more than once :)
Take care
MIKE

_________________
If this helped...please remember to rate it!


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 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.