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.  [ 5 posts ] 
Author Message
 Post subject: Mapping two classes to one table - bad idea?
PostPosted: Tue Oct 30, 2007 11:32 am 
Newbie

Joined: Tue May 15, 2007 3:53 pm
Posts: 9
I have a two tables in my database, a Company table with an ID and company name, and a CrossSell table with a companyId field, and several url strings. I've got them mapped so there are two classes mapped to that table: Company, and CompanyWithCrossSell, which inherits Company. I'm using two classes because Company is used frequently, but CompanyWithCrossSell is used seldom.

My problem is that when getting a list of companies (with Criteria query), I get every company twice, once as the Company class, and once as CompanyWithCrossSell. So, my question is, am I doing something wrong, or is this just a bad idea?


Classes:

Code:
public class IdValueTuple<TId, TVal>
{
   public virtual TId Id  { /* property get/set */ }
   public virtual TVal Value { /* property get/set */ }
}

public class Company : IdValueTuple<int, string>
{
   public override bool Equals(object obj)
   {
      Company other = obj as Company;
      if (other == null) return false;   // obj is null or not Company class
      if (this.Id == 0 || other.Id == 0)
     {
         // one or both Id's are transient, so compare Value
         return (this.Value == other.Value);
      }
      return (Id == other.Id);
   }

   public override int GetHashCode()
   {
      return Value.GetHashCode();
   }

   // also implements IComparable, ICloneable interfaces
}

public class CompanyWithCrossSell : Company
{
   public virtual CrossSell CrossSell { /* property get/set */ }
}

public class CrossSell
{
   public virtual int CompanyId { /* property get/set */ }
   public virtual string Url1 { /* property get/set */ }
   // ... and so on
}




Mapping documents:
Code:
   <class name="Company" table="company">
      <id name="Id" column="id" type="int">
         <generator class="sequence">
            <param name="sequence">company_id</param>
         </generator>
      </id>
      <property name="Value" column="company" />
   </class>

   <class name="CompanyWithCrossSell" table="company">
      <id name="Id" column="id" type="int">
         <generator class="sequence">
            <param name="sequence">company_id</param>
         </generator>
      </id>
      <property name="Value" column="company" />
      <one-to-one name="CrossSell" class="CrossSell"/>
   </class>

   <class name="CrossSell" table="crossSell">
      <id name="CompanyId" column="companyid" type="int">
         <generator class="assigned"/>
      </id>
      <property name="Url1" column="url1" type="StringClob" />
      <property name="Url2" column="url2" type="StringClob" />
      <property name="Url3" column="url3" type="StringClob" />
   </class>


Code between sessionFactory.openSession() and session.close():
ICriteria search = session.CreateCriteria( typeof(Company) );
search.AddOrder( Order.Asc("Value") );
List<Company> list = (List<Company>)search.List<Company>();

NHibernate version:
1.2.0GA

Name and version of the database you are using:
Oracle 10g
[/code]


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 30, 2007 11:58 am 
Newbie

Joined: Mon Jul 18, 2005 9:04 am
Posts: 11
Mapping 2 object to the same table in that way is generally bad I believe.
For example, nhibernate will keep a cache of the state of your object. If you change a property to object Company, this will not be reflected in your second object.
Because your second company object inherits from the first, you should map it as a subclass, for example using the "joined-subclass" method.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 30, 2007 4:37 pm 
Newbie

Joined: Tue May 15, 2007 3:53 pm
Posts: 9
using joined-subclass fixed my problem with duplicates in the list, but caused another problem; before, if I called session.Load<CompanyWithCrossSell>(id) where there was no corresponding entry in the CrossSell table, it would give me an object to work with anyway. Now, it is throwing an ObjectNotFoundException.

I tried working around it like this:

Code:
try
{
   CompanyWithCrossSell company = _getDataRecord<CompanyWithCrossSell>( companyId );
   sCompany.Text = company.Value;
   if ( company.CrossSell != null ) {
      // do other stuff
   }
}
catch (ObjectNotFoundException)
{
   // no cross-sell records exists yet, get plain company record
   Company temp =  _getDataRecord<Company>( companyId );
   sCompany.Text = temp.Value;
}


this is throwing the exception:
(NHibernate.ObjectNotFoundException: No row with the given identifier exists: 299, of class: CompanyWithCrossSell)
on the line where I'm calling _getDataRecord<Company> as a workaround in the catch() block


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 01, 2007 7:38 pm 
Newbie

Joined: Mon Jul 18, 2005 9:04 am
Posts: 11
I think I mis-understood your question.
I think the problem is with your model, not with nHibernate or the mapping.
It is normal that nHibernate will tell you there is no such an object as what you ask for is not there. The use of a try/catch block like that is totally unacceptable.

I thought you meant that CompanyWithCrossSell is a special type of Company, hence it inherits from it (by the way, please use interfaces to model this).
You probably want composition rather than inheritance.
What you probably mean is that a Cross sell is a property of a company, which you should model as property.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 02, 2007 9:38 am 
Senior
Senior

Joined: Thu Feb 09, 2006 1:30 pm
Posts: 172
If it helps I don't think you should be using the joined-subclass mapping. As I understand it this is all in one table. In that case you use the subclass mapping instead. However, you will still load duplicate items when you select customers.

To address this you must add the where clause to your class mapping to properly filter when one item is loaded versus the other.

Alternatively just put that property on the customer and then make the joined property a proxy if you are concerned about performance.

There are many options which should work for you.


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