View Full Version : Mapping NHibernate Generics classes
Hi I am pretty new in Spring.net & Nhibernate. I tried to use Generic DAO interfaces and Generic DAO classes in NHibernate, then got stuck. How can i map this Dao interface via Spring.net and inject them into a web app?
My Code is is below:
1) Generic Dao interface.
<code>
public interface IGenericDao<T, IdT>
{
T FindById(IdT id);
IList<T> FindAll();
T Save(T instance);
T SaveOrUpdate(T instance);
void Delete(T instance);
}
</code>
2) Dao factory
<code>
public interface ICustomerDao : IGenericDao<Customer, string> { }
public interface IOrderDao : IGenericDao<Order, long> { }
</code>
3) Generic NHibernate Dao class
<code>
public class GenericNHibernateDao<T, IdT> : HibernateDaoSupport, IGenericDao<T, IdT>
{
public T FindById(IdT id)
{
return HibernateTemplate.Load<T>(persitentType, id);
}
public IList<T> FindAll()
{
return HibernateTemplate.LoadAll(persitentType) as IList<T>;
}
public T Save(T instance)
{
HibernateTemplate.Save(instance);
return instance;
}
public T SaveOrUpdate(T instance)
{
HibernateTemplate.SaveOrUpdate(instance);
return instance;
}
public void Delete(T instance)
{
HibernateTemplate.Delete(instance);
}
private Type persitentType = typeof(T);
}
</code>
4) NHibernate Dao factory
<code>
public class HibernateCustomerDao : GenericNHibernateDao<Customer, string> { }
public class HibernateOrderDao : GenericNHibernateDao<Order, long> { }
</code>
boriska
04-18-2007, 08:05 AM
Hi,
the code you cited seems to be from a popular article at codeproject.com, isn't it?:)
I played with a generic DAO approach too but in a different way:
see for more http://forum.springframework.net/showpost.php?p=6340&postcount=2
Regards,
Boris
You are right. It's an example from codeproject. :)
Actually that example only illutrate how it works on NHibenate, I want to integrate it with Spring.net. If i don't use generic, create DAO class and interface indivirually, it works fine, like the example SpringAir. When i try to use Generic to the same interface, it got error.
My object definitation is
<!-- Abstract NHibernate Dao Support -->
<object id="hibernateDaoSupport"
type="Spring.Data.NHibernate.Support.HibernateDaoSupport , Spring.Data.NHibernate12"
abstract="true">
<property name="sessionFactory" ref="SessionFactory"/>
</object>
<object id="customerDao"
type="Spring.Northwind.Dao.NHibernate.GenericNHibernateD ao<Spring.Northwind.Domain.Customer,string>, Spring.Northwind.Dao.NHibernate"
parent="hibernateDaoSupport">
</object>
<object id="orderDao"
type="Spring.Northwind.Dao.NHibernate.HibernateOrderDao, Spring.Northwind.Dao.GenericNHibernateDao<Spring.N orthwind.Domain.Order,long>"
parent="hibernateDaoSupport">
</object>
Stack Trace:
[PropertyAccessExceptionsException: PropertyAccessExceptionsException (1 errors); nested PropertyAccessExceptions are:
[Spring.Objects.TypeMismatchException: Cannot convert property value of type [Spring.Northwind.Dao.NHibernate.GenericNHibernateD ao`2[[Spring.Northwind.Domain.Customer, Spring.Northwind.Dao, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]] to required type [Spring.Northwind.Dao.ICustomerDao] for property 'CustomerDao'., Inner Exception: Spring.Objects.TypeMismatchException: Cannot convert property value of type [Spring.Northwind.Dao.NHibernate.GenericNHibernateD ao`2[[Spring.Northwind.Domain.Customer, Spring.Northwind.Dao, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]] to required type [Spring.Northwind.Dao.ICustomerDao] for property 'CustomerDao'.
at Spring.Util.ConversionUtils.ConvertValueIfNecessar y(Type requiredType, Object newValue, String propertyName) in c:\projects\daily\Spring.Net\src\Spring\Spring.Cor e\Util\ConversionUtils.cs:line 133]]
Spring.Objects.ObjectWrapper.SetPropertyValues(IPr opertyValues propertyValues, Boolean ignoreUnknown) in c:\projects\daily\Spring.Net\src\Spring\Spring.Cor e\Objects\ObjectWrapper.cs:376
Spring.Objects.ObjectWrapper.SetPropertyValues(IPr opertyValues pvs) in c:\projects\daily\Spring.Net\src\Spring\Spring.Cor e\Objects\ObjectWrapper.cs:304
Spring.Objects.Factory.Support.AbstractAutowireCap ableObjectFactory.ApplyPropertyValues(String name, RootObjectDefinition definition, IObjectWrapper wrapper, IPropertyValues properties) in c:\projects\daily\Spring.Net\src\Spring\Spring.Cor e\Objects\Factory\Support\AbstractAutowireCapableO bjectFactory.cs:323
[ObjectCreationException: Error creating object with name '/Web/Northwind/ViewCustomers.aspx' defined in 'config [objects]' : Error setting property values: PropertyAccessExceptionsException (1 errors); nested PropertyAccessExceptions are:
[Spring.Objects.TypeMismatchException: Cannot convert property value of type [Spring.Northwind.Dao.NHibernate.GenericNHibernateD ao`2[[Spring.Northwind.Domain.Customer, Spring.Northwind.Dao, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]] to required type [Spring.Northwind.Dao.ICustomerDao] for property 'CustomerDao'., Inner Exception: Spring.Objects.TypeMismatchException: Cannot convert property value of type [Spring.Northwind.Dao.NHibernate.GenericNHibernateD ao`2[[Spring.Northwind.Domain.Customer, Spring.Northwind.Dao, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]] to required type [Spring.Northwind.Dao.ICustomerDao] for property 'CustomerDao'.
at Spring.Util.ConversionUtils.ConvertValueIfNecessar y(Type requiredType, Object newValue, String propertyName) in c:\projects\daily\Spring.Net\src\Spring\Spring.Cor e\Util\ConversionUtils.cs:line 133]]
Spring.Objects.Factory.Support.AbstractAutowireCap ableObjectFactory.ApplyPropertyValues(String name, RootObjectDefinition definition, IObjectWrapper wrapper, IPropertyValues properties) in c:\projects\daily\Spring.Net\src\Spring\Spring.Cor e\Objects\Factory\Support\AbstractAutowireCapableO bjectFactory.cs:328
Spring.Objects.Factory.Support.AbstractAutowireCap ableObjectFactory.PopulateObject(String name, RootObjectDefinition definition, IObjectWrapper wrapper) in c:\projects\daily\Spring.Net\src\Spring\Spring.Cor e\Objects\Factory\Support\AbstractAutowireCapableO bjectFactory.cs:419
Spring.Objects.Factory.Support.AbstractAutowireCap ableObjectFactory.ConfigureObject(String name, RootObjectDefinition definition, IObjectWrapper wrapper) in c:\projects\daily\Spring.Net\src\Spring\Spring.Cor e\Objects\Factory\Support\AbstractAutowireCapableO bjectFactory.cs:1827
Spring.Objects.Factory.Support.AbstractAutowireCap ableObjectFactory.CreateObject(String name, RootObjectDefinition definition, Object[] arguments, Boolean allowEagerCaching) in c:\projects\daily\Spring.Net\src\Spring\Spring.Cor e\Objects\Factory\Support\AbstractAutowireCapableO bjectFactory.cs:744
Spring.Objects.Factory.Support.AbstractAutowireCap ableObjectFactory.CreateObject(String name, RootObjectDefinition definition, Object[] arguments) in c:\projects\daily\Spring.Net\src\Spring\Spring.Cor e\Objects\Factory\Support\AbstractAutowireCapableO bjectFactory.cs:634
Spring.Objects.Factory.Support.AbstractObjectFacto ry.GetObject(String name, Type requiredType, Object[] arguments) in c:\projects\daily\Spring.Net\src\Spring\Spring.Cor e\Objects\Factory\Support\AbstractObjectFactory.cs :257
Spring.Objects.Factory.Support.AbstractObjectFacto ry.GetObject(String name, Object[] arguments) in c:\projects\daily\Spring.Net\src\Spring\Spring.Cor e\Objects\Factory\Support\AbstractObjectFactory.cs :1267
Spring.Objects.Factory.Support.AbstractObjectFacto ry.GetObject(String name) in c:\projects\daily\Spring.Net\src\Spring\Spring.Cor e\Objects\Factory\Support\AbstractObjectFactory.cs :1227
Spring.Context.Support.AbstractApplicationContext. GetObject(String name) in c:\projects\daily\Spring.Net\src\Spring\Spring.Cor e\Context\Support\AbstractApplicationContext.cs:10 86
Spring.Web.Support.PageHandler.System.Web.IHttpHan dler.ProcessRequest(HttpContext context) in c:\projects\daily\Spring.Net\src\Spring\Spring.Web \Web\Support\PageHandlerFactory.cs:248
System.Web.CallHandlerExecutionStep.System.Web.Htt pApplication.IExecutionStep.Execute() +154
System.Web.HttpApplication.ExecuteStep(IExecutionS tep step, Boolean& completedSynchronously) +64
thanks
Hi THE.
It is quite simple to use generics in DAO.
In my project it looks as follows:
IDao.cs
public interface IDao
{
T Store <T>(T obj);
...
}
Dao.cs
using NHibernate;
using Spring.Data.NHibernate;
using Spring.Data.NHibernate.Generic.Support;
...
public class Dao
: HibernateDaoSupport,
IDao
{
public T Store <T>(T obj)
{
HibernateTemplate.SaveOrUpdateCopy(obj);
return obj;
}
...
}
Dao.xml
<object id="Dao" type="MyProj.DAO.Dao, MyProj.DAO">
<property name="SessionFactory" ref="SessionFactory" />
</object>
Do you use Spring.Data.NHibernate.Generic.Support or Spring.Data.NHibernate.Support?
Best regards,
Nop.
Erich Eichinger
04-19-2007, 09:38 PM
Hi THE,
I guess your ViewCustomers.aspx contains a property
public ICustomerDao CustomerDao
{
set { ... }
}
The problem: According to the code-snippets you posted, GenericHibernateDao<Customer,string> does not implement ICustomerDao - it only implements IGenericDao<Customer, string>
Thus if you change your property to
public IGenericDao<Customer, string> CustomerDao
{
set { ... }
}
I expect, that everything is working as you want it to.
-Erich
Hi Erich,
It works after i implemented it as your comment. Thanks so much (Y)
However, I am still wondering, i already have the definition
-------------------------------------------------------------------
public interface ICustomerDao : IGenericDao<Customer, string> { }
-------------------------------------------------------------------
Why can't it implement ICustomerDao in ViewCustomer.aspx directly, but use
-------------------------------------------------------------------
public IGenericDao<Customer, string> CustomerDao
-------------------------------------------------------------------
instead??
I tried two different implementations to inject objects
1)
<object id="customerDao"
type="Spring.Northwind.Dao.NHibernate.GenericNHibernateD ao<Spring.Northwind.Domain.Customer,string>, Spring.Northwind.Dao.NHibernate"
parent="hibernateDaoSupport">
</object>
<object id="orderDao"
type="Spring.Northwind.Dao.NHibernate.GenericNHibernateD ao<Spring.Northwind.Domain.Order,long>, Spring.Northwind.Dao.NHibernate"
parent="hibernateDaoSupport">
</object>
2)
<object id="customerDao"
type="Spring.Northwind.Dao.NHibernate.HibernateCustomerD ao, Spring.Northwind.Dao.NHibernate"
parent="hibernateDaoSupport">
</object>
<object id="orderDao"
type="Spring.Northwind.Dao.NHibernate.HibernateOrderDao, Spring.Northwind.Dao.NHibernate"
parent="hibernateDaoSupport">
</object>
those two implementations both works for Erich's solution, but both don't work for my solution(implement ICustomerDao in ViewCustomer.aspx directly). weird??
By the way, I like this forum, i can get correct solution here.
And also which solution is Spring.net recommended, generic dao class defination or regular dao classes?
boriska
04-20-2007, 08:13 AM
Hi,
1) I think that we can have a genericDao and subclasses("customDAO's" ) that extend it. Then customDAO's can perform simple db operations contained in the genericDao and they hold finder methods (HQL, Criteria API- or "pure" SqlQuery calls) as well.
2) Alternatively we could generate all customDAO’s at runtime and use introductions to add a number of finder methods to the generic DAO class.
If you prefer to write less explicit code and want to configure application through xml configurations you can do it this way.
On the other hand having finder methods explicitly in customDao’s is in my opinion more transparent.
Let’s talk about it!
Regards,
Boris
Erich Eichinger
04-20-2007, 06:18 PM
Hi THE,
Why can't it implement ICustomerDao in ViewCustomer.aspx directly, but use
-------------------------------------------------------------------
public IGenericDao<Customer, string> CustomerDao
-------------------------------------------------------------------
instead??
This is because GenericNHibernateDao<Customer, string> simply does not implement ICustomerDao - it only implements IGenericDao<Customer, string>!
You can make this work like this:
public interface ICustomerDao
: IGenericDao<Customer, string>
{ }
public class HibernateCustomerDao
: GenericNHibernateDao<Customer, string>
, ICustomerDao // <- note the additional interface here
{ }
then you can use ICustomerDao as your property type and use
<object id="customerDao"
type="Spring.Northwind.Dao.NHibernate.HibernateCus tomerDao, Spring.Northwind.Dao.NHibernate"
parent="hibernateDaoSupport">
</object>
<object type="ViewCustomers.aspx">
<property name="CustomerDao" ref="customerDao" />
</object>
to wire them.
cheers,
Erich
Erich Eichinger
04-20-2007, 06:26 PM
And also which solution is Spring.net recommended, generic dao class defination or regular dao classes?
There is no recommendation. Generics tend to be overused and make your code cluttered. On the other hand they provide type-safety especially when used with collections, lists etc.
Personally I prefer writing ICustomerDao instead of IGenericDao<Customer,string> in my code. Thus at least I'd derive some class and interface ICustomerDao and HibernateCustomerDao from generic baseclasses before using them in my code as we have exercised above. I think it makes the "logic" code more readable. But this basically is a matter of taste. Ideally code should be self explaining. That's the driving criteria...
just my little opinion ;-)
Erich
Hi Erich,
the solution in #9 is exactly what i need. i implemented all the code, but forgot the interface declaration.
public class HibernateCustomerDao
: GenericNHibernateDao<Customer, string>
, ICustomerDao // <- i forget to declare the interface here
{ }
Once i added this interface, all works! :)
Cheers!
Terry
I agree your opinion. It's better to implement generic dao class, then extend it and then expose it by different interfaces. that is gentle way to make code.
Cheers!
One more question:
How can i make generic FindAll method via HibernateTemplate? right now i can only make it using ICriteria.
public IList<T> FindAll()
{
ICriteria criteria = session.CreateCriteria(persitentType);
return criteria.List<T>();
}
I tried it in this way, but it looks not nice
public IList<T> FindAll()
{
return MakeGenericList(HibernateTemplate.LoadAll(persiten tType));
}
private List<T> MakeGenericList(System.Collections.IList listObjects)
{
List<T> convertedList = new List<T>();
foreach (object listObject in listObjects)
{
convertedList.Add((T)listObject);
}
return convertedList;
Not sure it is a simple question?
jborralho
04-27-2007, 02:56 PM
Use Spring.Data.NHibernate.Generic.
That way you have the generic HibernateTemplate (and a classic instance inside) with:
HibernateTemplate.LoadAll<T>()
greets
Thanks for your reply, Jborralho.
However it doesn't have HibernateTemplate.LoadAll<T>(). It has HibernateTemplate.LoadAll(), but returns System.Collection.List type.
Ismar Slomic
05-09-2007, 12:27 AM
Thanks for your reply, Jborralho.
However it doesn't have HibernateTemplate.LoadAll<T>(). It has HibernateTemplate.LoadAll(), but returns System.Collection.List type.
Hi!
You probably use the non-generic classes. You have to use the generic namespace:
using Spring.Data.NHibernate.Generic.Support;
Hope it helps!
Regards Ismar
vBulletin® v3.7.3, Copyright ©2000-2008, Jelsoft Enterprises Ltd.