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: <column name="'fixed value'"> throws an exce
PostPosted: Mon Sep 25, 2006 9:42 pm 
Newbie

Joined: Mon Sep 25, 2006 9:00 pm
Posts: 3
Hi!

nHibernate version 1.0.2.0

I am trying to use workaround provided here http://forum.hibernate.org/viewtopic.php?t=938218 as workaround for the problem of 'mapping the association from the entity class to the subclass by specifying (1) a many-to-one association to the named subclass in the entity class's mapping, and (2) having a single column in the entity class's table, which contains the subclass-specific id of the associated subclass instance'.

Workaround proposed was to use fixed value for a discriminator column, e.g.

<many-to-one name="Country" class="Country">
<column name="'C'"/>
<column name="Country" />
</many-to-one>

But I am receiving an exception, which looks like an nhibernate bug:

Code:
[SqlException (0x80131904): Incorrect syntax near 'C'.]
   System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection) +95
   System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) +82
   System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj) +346
   System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) +3244
   System.Data.SqlClient.SqlDataReader.ConsumeMetaData() +52
   System.Data.SqlClient.SqlDataReader.get_MetaData() +130
   System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) +371
   System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async) +1121
   System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result) +334
   System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) +45
   System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) +162
   System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior) +35
   System.Data.Common.DbCommand.System.Data.IDbCommand.ExecuteReader() +29
   NHibernate.Impl.BatcherImpl.ExecuteReader(IDbCommand cmd) +92
   NHibernate.Loader.Loader.GetResultSet(IDbCommand st, RowSelection selection, ISessionImplementor session) +238
   NHibernate.Loader.Loader.DoQuery(ISessionImplementor session, QueryParameters queryParameters, Object optionalObject, Object optionalId, Object[] optionalCollectionKeys, Boolean returnProxies) +354
   NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor session, QueryParameters queryParameters, Object optionalObject, Object optionalId, Object[] optionalCollectionKeys, Boolean returnProxies) +89
   NHibernate.Loader.Loader.DoList(ISessionImplementor session, QueryParameters queryParameters) +45
   NHibernate.Loader.Loader.List(ISessionImplementor session, QueryParameters queryParameters, ISet querySpaces, IType[] resultTypes) +344
   NHibernate.Hql.QueryTranslator.List(ISessionImplementor session, QueryParameters queryParameters) +112
   NHibernate.Impl.SessionImpl.Find(String query, QueryParameters parameters) +265

[ADOException: Could not execute query]
   NHibernate.Impl.SessionImpl.Find(String query, QueryParameters parameters) +327
   NHibernate.Impl.SessionImpl.Find(String query, Object[] values, IType[] types) +62
   NHibernate.Impl.SessionImpl.Find(String query) +45
   MXL.DataAccess.HttpDAL`1.Find(String query) in C:\source\eMin5\eMinerva\MXL.DataAccess\HttpDAL.cs:216
   MXL.Business.Services.StudentService.Find(String query) in C:\source\eMin5\eMinerva\MXL.Business.Services\StudentService.cs:56
   eMinerva.Business.DataSources.StudentDataSource.Search(String value, String sortParameter) in ...\StudentDataSource.cs:50
...



The part of a query throws an exception looks like this:

select Address.City, Address.'C', Address.Country from ...

e.g. using fixed value with alias, which raises an exception on an SQL Server.

Is it a bug in nHibernate? Is there another workaround for this problem?
Using proposed <formula>'C'</formula> raises a mapping exception.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 25, 2006 10:04 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
That can't be an hibernate exception, as it's the generated SQL that's having the problem, and the generated SQL contains exactly what you told it to. Obviously SQL (or at least your flavour of it) can't handle stringified column names. Use name="C" or name="[C]", whichever is preferred by your flavour of SQL.

_________________
Code tags are your friend. Know them and use them.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 25, 2006 11:00 pm 
Newbie

Joined: Mon Sep 25, 2006 9:00 pm
Posts: 3
But I need to specify a value, not a column name. "C" or [C] - is a column name, but I need a value 'C'.

Sorry, but here is more details about the problem:

2 tables, ClassificationCode and Address:
Code:
CREATE TABLE A_ClassificationCode(
   CodeType nvarchar(50) ,
   Code nvarchar(50) ,
   Name nvarchar(50) ,
CONSTRAINT [PK_A_ClassificationCode] PRIMARY KEY (CodeType ASC, Code ASC)

CREATE TABLE A_Address(
   Address_Id int IDENTITY(1,1) ,
   AddressTypeCode nvarchar(50),
   CityCode nvarchar(50) ,
   CountryCode nvarchar(50) ,
   Postcode nvarchar(10) ,
CONSTRAINT PK_A_Address PRIMARY KEY (Address_Id ASC)

ClassificationCode contains all cities, countries, addresstypes. CodeType is a discriminator column.

Mappings are as following:

Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
   <class name="ClassificationCode" table="A_ClassificationCode" lazy="true" discriminator-value="zzz">
      <composite-id name="Id" class="ClassificationCode_Id">
         <key-property name="CodeType" access="property" column="CodeType" type="String" length="50"/>
         <key-property name="Code" access="property" column="Code" type="String" length="50"/>
      </composite-id>
      <discriminator column="CodeType" type="string" force="true" insert="false"/>
      <property name="Name" column="Name" type="String" length="50" />
      <subclass name="State" discriminator-value="State" proxy="State" lazy="true"/>
      <subclass name="Country" discriminator-value="Country" proxy="Country" lazy="true"/>
      <subclass name="AddressType" discriminator-value="AddressType" proxy="AddressType" lazy="true"/>
   </class>
</hibernate-mapping>


Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
   <class name="Address" table="A_Address" lazy="true">
      <id name="Id" column="Address_Id" >
         <generator class="native" />
      </id>
      <property name="Postcode" column="Postcode" type="String" length="50" />
      <many-to-one name="AddressType" class="AddressType">
         <column name="'AddressType'"/>
         <column name="AddressTypeCode" />
      </many-to-one>
      <many-to-one name="Country" class="Country">
         <column name="'Country'"/>
         <column name="CountryCode" />
      </many-to-one>
      <many-to-one name="City" class="City">
         <column name="'City'"/>
         <column name="CityCode" />
      </many-to-one>
   </class>
</hibernate-mapping>


Unfortunately, I can't change DB structure.

I have to specify somehow <column name="'AddressType'"/> to have 2 columns in a many-to-one for Address entity, because PK of a ClassificationCode consists of 2 columns. But it throws an exception I described above. I receive this exception when I try to access an AddressType, City or Country property of an instance of Address, like
address.Country.Name or address.AddressType.Name.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 25, 2006 11:56 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
My bad, I stopped reading too soon.

You can't use a variable as a column name. Best you can do is define a polymorphic mapping, and several classes (or one class mapped several times, distinguished via entity-name). Something like
Code:
<class name="BaseAddress" ...>
  ...
  <property name="Code" column="AddressTypeCode" .../>
  <subclass name="ConcreteClass1" discriminator-value="1" class="AddressImpl" entity-name="AddressType1" ...>
    ...
    <property name="Type" column="AddressColumn1" .../>
    <property name="Country" column="AddressCountry1" .../>
    <property name="City" column="AddressCity1" .../>
  </subclass>
  <subclass name="ConcreteClass2" discriminator-value="2" class="AddressImpl" entity-name="AddressType2" ...>
    <property name="Type" column="AddressColumn2" .../>
    <property name="Country" column="AddressCountry2" .../>
    <property name="City" column="AddressCity2" .../>
    ...
  </subclass>
</class>
Then in other mappings that refer to any kind of address, you can use <many-to-one class="BaseAddress"/>, and in mappings that refer only to type1 addresses, you can use <many-to-one entity-name="AddressType1"/>. If you a separate class for each type, you can ignore the entity-name stuff and just use class="??" the entire time.

I didn't notice earlier that this is an NHibernate topic.. I hope that entity-name is in hibernate2. If it's not, then you'll have to use a different implementation class for each subclass.

_________________
Code tags are your friend. Know them and use them.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Sep 26, 2006 1:01 am 
Newbie

Joined: Mon Sep 25, 2006 9:00 pm
Posts: 3
Thank you very much for the idea. I removed discriminator column from the key mapping and It works!

But I have one small issue left.

When I create new AddressType (actually, any instance of the subclass), I have to specify discriminator value directly: to assign it to the CodeType property or to have it initialized in a class ctor:
Code:
public class AddressType:ClassificationCode
{
   public AddressType(){ CodeType = 'addressType'; }
}


I would like to have it assigned by nHiberbate, if possible. Can I do it somehow?

I use following mapping:
Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
   <class name="ClassificationCode" table="A_ClassificationCode" lazy="true" discriminator-value="zzz">
      <id name="Id" column="Code" type="String" length="50">
         <generator class="assigned" />
      </id>
      <discriminator column="CodeType" type="string" force="true" insert="false"/>
      <property name="CodeType" column="CodeType" type="String" length="50" />
      <property name="Name" column="Name" type="String" length="50" />
      <subclass name="State" discriminator-value="State" proxy="State" lazy="true" />
      <subclass name="Country" discriminator-value="Country" proxy="Country" lazy="true" />
      <subclass name="AddressType" discriminator-value="AddressType" proxy="AddressType" lazy="true" />
   </class>
</hibernate-mapping>


<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
   <class name="Address" table="A_Address" lazy="true">
      <id name="Id" column="Address_Id" >
         <generator class="native" />
      </id>
      <property name="Postcode" column="Postcode" type="String" length="50" />
      <many-to-one name="AddressType" class="AddressType" column="AddressTypeCode"/>
      <many-to-one name="Country" class="Country" column="CountryCode"/>
   </class>
</hibernate-mapping>


Top
 Profile  
 
 Post subject:
PostPosted: Tue Sep 26, 2006 1:26 am 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
The class doesn't need to know anything about the discriminator. The value isn't written to or read from the class at any point, the value in the discriminator-value attribute in the mapping file is the one that's used. If you want it there for your own application code's use, then you have to put it there yourself.

In java, this would normally be done by querying the class of the object, using instanceof. Or there could be a class member/method (a "static" member) that would store that info.

_________________
Code tags are your friend. Know them and use them.


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.