Hash

Entries tagged as ‘nhibernate’

Creating one-to-many relationship in NHibernate

March 31, 2009 · 9 Comments

We have recently brought in NHibernate in our environment and I was the first one in the team to do something real with it. It was going perfect until this one-to-many relationship and then I had to consult the architect in UK to get it going :( Infact I successfully implemented many-to-many but could not do one-to-many . *&#%&*#W(*(*&%#

Anyways, we had a class SearchCritera having a list of SearchCriterion. The mapping file looked like:

<class name="BusinessObjects.Search.SearchDocumentCriteria" table="searchdocumentcriteria">
<id name="Id" column="id">
<generator class="sequence">
<param name="sequence">pc_searchdocumentcriteria</param>
</generator>
</id>
<bag name="Criteria" lazy="false" cascade="all" inverse="true">
<key column="criteriaid"/>
<one-to-many class="BusinessObjects.Search.SearchDocumentCriterion"/>
</bag>
</class>
<class name="BusinessObjects.Search.SearchDocumentCriterion" table="searchdocumentcriterion">
<id name="Id" column="id">
<generator class="sequence">
<param name="sequence">pc_searchdocumentcriterion</param>
</generator>
</id>
<property name="FieldName" column="fieldname" type="string"/>
<many-to-one name="Id" class="BusinessObjects.Search.SearchDocumentCriteria" column="criteriaid" not-null="true"/>
<bag name="Expression" lazy="false" cascade="all" inverse="true">
<key column="criterionid"/>
<one-to-many class="Search.SearchDocumentCriterionOperatorValue"/>
</bag>
</class>

Look at the red line, it maps back to the parent class’s column Id. This is what I found in the manual and an example on the internet as well. But we were getting the error:

Unknown entity class: System.Int32

Later we found that we need to have a parent reference in the child class as well which make the relationship 2-way. So we added the following property in the SearchDocumentCriterion class:

public virtual SearchDocumentCriteria Parent { get; set; }

And the following change in the mapping file:

<many-to-one name="Parent" class="BusinessObjects.Search.SearchDocumentCriteria" column="criteriaid" not-null="true"/>

Note the Parent property instead of Id property. This solved the problem :D Anyone having a better solution for one-to-many relationship in NHibernate? Yes, I don’t like the two-way relationship.

 

 


Share this post : digg it! Facebook it! live it! reddit! technorati! yahoo!

Categories: .NET · CodeProject
Tagged: , , , , , , ,

View SQL generated by NHibernate

November 25, 2008 · Leave a Comment

NHibernate has a built-in mechanism to log all SQL statements generated. It has a configuration parameter “show_sql” which should be set to true. NHibernate will throw all statements to Console.out if this is true. So a console application can easily display all statements but what about the web application?

An easy way is to use the NUnit console which has a separate tab for all Console.out output. If you do not use NUnit work out with log4net.

Categories: .NET
Tagged: , , , ,

Creating one-to-one relationship in NHibernate

November 18, 2008 · Leave a Comment

A one-to-one relationship between two tables can be created by:

  • Adding a column to the parent table with some unique ID of the child table
  • Without any extra column: just inserting the same PK value in both tables

NHibernate supports the second method (correct me) and you can create this relationship using the “foreign” type ID generator and the <one-to-one> tags in both mappings. Today I created the following mappings for two classes named Document and DocumentStatus.

<class name="Document" table="documents">
    <id name="Id" column="id">
          <generator class="foreign">
               <param name="property">Status</param>
          </generator>
    </id>
    <one-to-one name="Status" class="DocumentStatus" constrained="true"/>
    ... other properties ...
</class>

The trick here is just the foreign ID generator class. Now the mapping for DocumentStatus would be fairly simple.

<class name="DocumentStatus" table="documentstatus">
    <id name="Id" column="id">
       ... any generator class ...
    </id>
    <one-to-one name="Document" class="Document"/>
    ... other properties ...
</class>

The classes will have a property of the corresponding type to map this relationship so you can navigate both ways.

class Document {
... other stuff ...
DocumentStatus Status;
}
class DocumentStatus {
... other stuff ...
Document Document;
}

Whenver you insert a new object in Document, the corresponding DocumentStatus object will be created and its PK will be assigned to Document object as well.

Great Stuff!

Categories: .NET
Tagged: , , , , , , , ,

Persisting Custom Data Types with NHibernate

November 14, 2008 · Leave a Comment

NHibernate provides native support for primitive types/enumerations only. What if I want to save something like a custom data type, say for example a System.Uri object? NHibernate provides a fairly simple way to do that which is an interface actually called IUserType. It has got a whole bunch of methods which should be implemented by your class.

    public interface IUserType
    {
        SqlType[] SqlTypes { get; }
        System.Type ReturnedType { get; }
        bool Equals( object x, object y );
        object NullSafeGet( IDataReader rs, string[] names, object owner );
        void NullSafeSet( IDbCommand cmd, object value, int index );
        object DeepCopy( object value );
        bool IsMutable { get; }
    }

The following method of the interface tells the data base type:

public SqlType[] SqlTypes
{
get
{
// We store our Uri in a single column in the database that can contain a string
SqlType[] types = new SqlType[1];
types[0] = new SqlType(DbType.String);
return types;
}
}

And this method tells the .NET type to be built for the value.

public System.Type ReturnedType
{
get { return typeof(Uri); }
}

This is how you build the .NET datatype from the value:

public object NullSafeGet(IDataReader rs, string[] names, object owner)
{
// We get the string from the database using the NullSafeGet used to get strings
string uriString = (string)NHibernateUtil.String.NullSafeGet(rs, names[0]);
// And save it in the Uri object. This would be the place to make sure that your string
// is valid for use with the System.Uri class, but i will leave that to you
Uri result = new Uri(uriString);
return result;
}

This is how you translate the value back to database type.

public void NullSafeSet(IDbCommand cmd, object value, int index)
{
// Set the value using the NullSafeSet implementation for string from NHibernateUtil
if (value == null)
{
NHibernateUtil.String.NullSafeSet(cmd, null, index);
return;
}
value = value.ToString(); // ToString called on Uri instance
NHibernateUtil.String.NullSafeSet(cmd, value, index);
}

The rest of the method are simple, and you can find them on the internet as well (where I found them :-) )

Categories: .NET
Tagged: , , ,