-->
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.  [ 2 posts ] 
Author Message
 Post subject: Composite-id key where components are references
PostPosted: Sat Jun 24, 2006 10:30 am 
Newbie

Joined: Tue Jun 06, 2006 10:45 pm
Posts: 5
Original post redacted, restatement of problem in next message.

Thanks,
Ian


Last edited by ipmcc on Sun Jun 25, 2006 10:51 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject: ... to elaborate
PostPosted: Sun Jun 25, 2006 10:45 pm 
Newbie

Joined: Tue Jun 06, 2006 10:45 pm
Posts: 5
I've flushed out a more detailed expression of the problem, so I figured, in the interests of clarity, I'd follow up my original post. The problem appears to come when trying to specify a <map />. I get a "Repeated column in mapping for collection" Exception, but I'm at a loss for how to write the mapping XML without having a repeated column.

Here's the table structure:
Code:
CREATE TABLE [dbo].[TestProduct] (
   [ProductID] [int] IDENTITY (1, 1) NOT NULL ,
   [Name] [nvarchar] (64) NOT NULL
)
CREATE TABLE [dbo].[TestStore] (
   [StoreID] [int] IDENTITY (1, 1) NOT NULL ,
   [Name] [nvarchar] (64) NOT NULL
)
CREATE TABLE [dbo].[TestPrice] (
   [StoreID] [int] NOT NULL ,
   [ProductID] [int] NOT NULL ,
   [Price] [decimal](19, 4) NOT NULL ,
   [NHVer] [int] NOT NULL
)


And here's the mapping so far, including the problem <map> tag:

Code:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
  <class name="Com.Ipmcc.LineSvc.Test.CompKeyTest.Store, Com.Ipmcc.LineSvc.Test" table="TestStore">
    <id name="StoreID" column="StoreID" type="Int32" unsaved-value="0">
      <generator class="identity" />
    </id>
    <version name="NHVer" column="NHVer" unsaved-value="negative"/>
    <property name="Name" column="Name" type="String" length="64"/>
    <map name="ProductToPrice">
      <key column="StoreID"/>
      <index-many-to-many column="ProductID"
      class="Com.Ipmcc.LineSvc.Test.CompKeyTest.Product, Com.Ipmcc.LineSvc.Test"/>
      <many-to-many class="Com.Ipmcc.LineSvc.Test.CompKeyTest.Price, Com.Ipmcc.LineSvc.Test">
        <column name="StoreID"/>
        <column name="ProductID"/>
      </many-to-many>    
    </map>
  </class>

  <class name="Com.Ipmcc.LineSvc.Test.CompKeyTest.Product, Com.Ipmcc.LineSvc.Test" table="TestProduct">
    <id name="ProductID" column="ProductID" type="Int32" unsaved-value="0">
      <generator class="identity" />
    </id>
    <property name="Name" column="Name" type="String" length="64"/>
   <!-- inverse map mapping to go here when I figure it out. -->
  </class>

  <class name="Com.Ipmcc.LineSvc.Test.CompKeyTest.Price, Com.Ipmcc.LineSvc.Test" table="TestPrice">
    <composite-id>
      <key-many-to-one name="NHStore" column="StoreID"
         class="Com.Ipmcc.LineSvc.Test.CompKeyTest.Store, Com.Ipmcc.LineSvc.Test" />
      <key-many-to-one name="NHProduct" column="ProductID"
         class="Com.Ipmcc.LineSvc.Test.CompKeyTest.Product, Com.Ipmcc.LineSvc.Test" />
    </composite-id>
    <version name="NHVer" column="NHVer" unsaved-value="negative"/>
    <property name="PriceVal" column="Price" type="Decimal" />
  </class>
</hibernate-mapping>


(C# entity object source at bottom)

Now, if I take the collection mapping out, everything works fine, so I'm comfortable that I've got the tricks of dealing with the composite key mapping. My unit tests are able to create and manipulate objects as expected, absent the collections. The goal here is to have an IDictionary on Store that takes a Product as an indexer and returns a Price object. The ultimate goal is to have a mirror image map on Product that takes a Store as an indexer and returns a price, but one step at a time.

The exception references StoreID as the 'repeated column' which I'm gathering stems from its use in bothe the <key/> element and the <many-to-many/> element. However, for how I read the documentation, this is all as it should be. The column referenced in <key/> is the FK (part of composite key) to the owning (collection-having) class, in this case StoreID. The <index-many-to-many/> element is the foreign key column for the collection index values, in this case ProductID. The <many-to-many/> element contains column elements for each column making up the composite primary key, which seemed in line with the example I found in Hibernate in Action.

So that's where I'm at. Is this a situation that's just not supported? If its just a semantic limitation, I was thinking perhaps I could map Price to a SQL view that had duplicates (with different names) of the StoreID and ProductID columns, so I could write the mapping without duplicating columns, but I figured I'd ask if there isn't some greater problem/challenge here that goes deeper.

Thanks for any input.
Ian

C# Entity object source:
Code:
public class Store
{
    private int m_StoreID;
    private string m_Name;
    private Int32 m_NHVer;
    private System.Collections.IDictionary m_ProductToPrice;

    public Store()
    {
        m_StoreID = 0;
        m_Name = String.Empty;
        m_NHVer = -1;
    }

    public string Name
    {
        get { return m_Name; }
        set
        {
            if (value != null && value.Length > 32)
                throw new ArgumentOutOfRangeException("Invalid value for Name", value, value.ToString());

            m_Name = value;
        }
    }

    public int StoreID
    {
        get { return m_StoreID; }
        set { m_StoreID = value; }
    }

    private Int32 NHVer
    {
        get { return m_NHVer; }
        set { m_NHVer = value; }
    }

    public System.Collections.IDictionary ProductToPrice
    {
        get
        {
            return this.m_ProductToPrice;
        }
        set
        {
            this.m_ProductToPrice = value;
        }
    }

}

public class Product
{
    private int m_ProductID;
    private string m_Name;

    public string Name
    {
        get { return m_Name; }
        set
        {
            if (value != null && value.Length > 32)
                throw new ArgumentOutOfRangeException("Invalid value for Name", value, value.ToString());

            m_Name = value;
        }
    }

    public int ProductID
    {
        get { return m_ProductID; }
        set { m_ProductID = value; }
    }

    public Product()
    {
        m_ProductID = 0;
        m_Name = String.Empty;
    }

}

public class Price
{
    private NHibernate.Generics.EntityRef<Product> m_Product;
    private NHibernate.Generics.EntityRef<Store> m_Store;
    private decimal m_Price;
    private Int32 m_NHVer;

    protected Price()
    {
        m_Product = new NHibernate.Generics.EntityRef<Product>();
        m_Store = new NHibernate.Generics.EntityRef<Store>();
        m_Price = 0.0M;
        m_NHVer = -1;
    }

    public Price(Store store, Product product) : this()
    {
        if (store == null) throw new ArgumentNullException("store");
        if (product == null) throw new ArgumentNullException("product");

        this.NHStore = store;
        this.NHProduct = product;
    }


    public Product Product
    {
        get { return NHProduct; }
    }
    private Product NHProduct
    {
        get { return m_Product.Value; }
        set { m_Product.Value = value; }
    }

    public Store Store
    {
        get { return NHStore; }
    }
    private Store NHStore
    {
        get { return m_Store.Value; }
        set { m_Store.Value = value; }
    }

    public decimal PriceVal
    {
        get { return m_Price; }
        set { m_Price = value; }
    }

    private Int32 NHVer
    {
        get { return m_NHVer; }
        set { m_NHVer = value; }
    }

    public override bool Equals(object obj)
    {
        if (this == obj)
            return true;
       
        Price theObj = obj as Price;
       
        if (theObj == null)
            return false;

        return (theObj.Store == this.Store && theObj.Product == this.Product && theObj.PriceVal == this.PriceVal && theObj.NHVer == this.NHVer);
    }

    public override int GetHashCode()
    {
        if (NHVer == -1)
            return base.GetHashCode();
        else
            return Store.GetHashCode() ^ Product.GetHashCode();

    }
}


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