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: NHibernate Encapsulation problem when using .NET web service
PostPosted: Mon Sep 25, 2006 5:52 am 
Newbie

Joined: Mon Sep 25, 2006 5:38 am
Posts: 3
Please excuse me if I am missing something obvious but I am new to NHibernate. I came across an issue with NHibernate and was looking for some advice as to whether I am doing something wrong.

We are building an N-Tiered, SOA based, system in .NET 2.0 and have decided to investigate using NHibernate for our persistence layer. We are using NHibernate-1.2.0.Alpha1 for our investigations.

Our architecture is as follows (from top to bottom):
- UI
- UI Controllers
- Service Façade
- Service Layer (web Services)
- Business Process Managers
- Domain Object Managers
- Domain Objects (DTOs)
- Persistence Layer
- Data Store.

The problem is one of encapsulation;

We would like to have the NHibernate code exist only in the Persistence Layer, so the Persistence layer contains all of the mapping files for mapping the Domain Objects to the data store etc. This means that our Domain Objects should not contain NHibernate specific types. All our collections, therefore, are defined as IList<T>s, rather than NHibernate.Collection.Generic.PersistentGenericBag<T>s.

This works fine until we reach the Service layer. Unfortunately, the .NET Xml Serializer cannot serialize Interfaces (as they are not concrete types) meaning that the Domain Objects cannot be exposed by the Web Services. As the IList<T> collections returned from NHibernate at run time (of type NHibernate.Collection.Generic.PersistentGenericBag<T>) cannot be cast to any concrete .NET type (e.g. List<T>, Collection<T>) this presents a bit of a problem…….

The work around we have come up with is to have two properties on the Domain Objects for each collection – one of type IList<T>, and another of type List<T> which uses the underlying variable of the List<T> property to construct the List<T> on first use, like this:

/// <summary>
/// Get/Set the Underlying Policy Collection Interface.
/// </summary>
private IList<PolicyDTO> PoliciesInterface
{
get
{
if (_policies != null)
return _policies;
else
return _policiesInterface;
}
set { _policiesInterface = value; }
}

/// <summary>
/// Get/Set the Policy Collection.
/// </summary>
public List<PolicyDTO> Policies
{
get
{
if (_policies == null)
_policies = new List<PolicyDTO>(_policiesInterface);

return _policies;
}
set { _policies = value; }
}

The PoliciesInterface property is defined as private and is therefore not picked up by the XML Serializer, but can still be used by NHibernate.

The other way of doing it seems to be to have two duplicate sets of Domain Objects, one utilising IList<T> and one utilising a concrete collection type like List<T> for their collections. The Domain Objects would then be mapped from one type to the other at either the Service or Persistence Layer level.

Both of these methods are pretty messy.

Other than that, the only solution seems to be to introduce the NHibernate namespaces to our Domain Objects, and use the NHibernate.Collection.Generic.PersistentGenericBag<T> concrete type throughout our code….

Am I missing something stupid? I can’t seem to find a clean way around this but I’m surprised I can’t find any existing posts about it……

Thanks in advance for your help,

Alex


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 25, 2006 10:04 am 
Regular
Regular

Joined: Mon May 16, 2005 1:35 am
Posts: 67
Personally, I wouldn't serialise your domain objects over the wire. If you're going for a service-oriented approach, then you should strongly consider using separate DTOs to your domain objects. Your domain objects should be fine-grained objects rich with domain logic, whereas your DTOs (or message classes) should be considerably simpler with little use of fine grained objects and no logic whatsoever.

The DTOs should be XML serialisable and version tolerant. Having a separate definition for your DTOs and domain objects allows you decouple your service interface from its implementation. This is vitally important from a maintainability aspect in an SOA world where you may have dozens of consumers of your service. You want to be able to update your service implementation without affecting its consumers.

Also, DTOs should not have any cyclic references - whereas domain objects (especially in parent-child relationships) use them extensively. This is because you should use literal encoded SOAP messages, meaning the messages are described using XSD - which has no ability to describe cyclic references.

Of course, DTOs are probably largely unnecessary if you're not building a distributed system (be it an SOA or otherwise). But since you've indicated you're using Web services I am assuming your going for a service-oriented approach.

So if you define your service interface independently of your domain objects, then your problem should disappear.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 25, 2006 11:53 am 
Newbie

Joined: Mon Sep 25, 2006 5:38 am
Posts: 3
Thanks for you swift reply.

I take your point, but we are using a fairly anaemic Domain Object Model whereby the Business Process Managers and Domain Object Managers contain most of the logic. The cyclical reference issue is being resolved by putting XmlIgnore attributes on the relevant properties.

This way we don't have to maintain two sets of similar objects (one for DTOs and one Domain Objects).

Thanks again for your reply.


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

Joined: Tue Aug 23, 2005 5:52 am
Posts: 335
Another option is to use RPC encoding rather than Doc Lit. This supports cyclic refrences. While it's not the encouraged standard it does work.

Symon.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Oct 07, 2006 10:53 pm 
Newbie

Joined: Mon Sep 25, 2006 2:07 am
Posts: 5
I get the similar issue when I try to use NH-1.2.0-Alpha.
In my scene, I defined two classes called class Parent and class Child.
The classes are defined like this:
public class Parent {
private string name;
private IList<Child> children;

public string Name{
get { return name;}
set { name = value;}
}

public IList<Child> Children{
get { return childern;}
set { children = value;}
}
}

public class Child{
private string name;
public string Name{
get { return name;}
set { name = value;}
}
}

Then I expose a web method to return a parent.

public Parent GetParentByName(string name){
ISession session = SessionFactory.GetSession();
Parent parent = session.Load<Parent>(name);
return parent;
}

In this way, I find that the type of parent.Children is PersisentGenericBag<T> instead of IList<T>. This causes the Serializer error.

So, how can I avoid this type cast so that I still get the parent.Children as IList<T>?

The solution provided by aaspinall is not a good way as I thought.
Is there any convient and clean way to do so?

Thanks very much.


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.