Given a rather simple structure in C#...
class Member
{
virtual string Email { get; set; }
virtual IList<Character> Characters { get; set; }
}
class Character
{
virtual string Name { get; set; }
}
interface IMemberRepository
{
MemberCreateStatus CreateMember(string email, string password);
bool ValidateMember(string email, string password);
Member RetrieveMember(string email);
void SaveMember(Member member);
}
interface ICharacterRepository
{
Character CreateCharacter(string name);
}
class MemberRepository : IMemberRepository
{
private readonly ISessionFactory sessionFactory;
public MemberRepository(ISessionFactory sessionFactory)
{
this.sessionFactory = sessionFactory;
}
//
public Member RetrieveMember(string email)
{
using(var session = sessionFactory.OpenSession())
{
return // member retrieval query
}
}
}
I have an ASP.NET MVC Applicat开发者_高级运维ion set up to use nHibernate (fluent configuration) and Castle.Windsor for IoC. This works fine and good, but herein lies the problem.
Lazy Loading
By default nature, IList<Character>
is lazy loaded in most any ORM (nHibernate, Entity Framework, etc) - Now this is not a bad thing, but I have run into a lot of confusion about how to approach this scenario.
- I want to add a
Character
to aMember
. Logically, I would useMember.Characters.Add(n);
and then callMemberRepository.SaveMember(m);
This is now problem because of the Unit of Work concept. I am supposed to create a Session
, do the work, and then destroy it after returning the results. That works fine ,but now I have the following object...
Member
- nHibernate Lazy Loaded Proxy (
IList<Character>
) Email
So then, I call var member = memberRepository.RetrieveMember(email);
in my Controller
, then I call member.Characters.Add(character);
And here is where the mess comes in.
The collection does not exist because it is lazy loaded, and the
Session
has been disposed.
So then, what is the answer? Sure, I could set my IList<Character>
to not Lazy Load, but that's just kind of stupid. One of the biggest ORM libraries in the world wouldn't be using lazy loading if impeded the basic design structure. How does this concept of UnitOfWork play into the IRepository<T>
pattern of IoC
and Injection Dependency?
My first thought was to just abstract the task to the Repository, and include an AddCharacter(Character character)
method to the IMemberRepository
, but I've now been told that is 'not what repositories are intended for'. So I'm not quite sure what to do from this point forward. Programatically I know many solutions, but I need to understand what the right solution is to keep with the standards.
nHibernate's Session
class has a method named Persist(object obj)
that I have made work with a UnitOfWork pattern - but from what I can tell, this method removes the Lazy Loading aspect of whatever it is applied to. If that were a by-call basis, it would be fine - but I'm of the understanding I cannot do that. I cannot talk to my Session
directly - only my Repository
classes are supposed to be allowed to communicate with the SessionFactory
. So I'm really pulling my hair out in confusion, now.
You should pass the ISession into the respository class constructor. The session-per-request pattern is usually used in a web application so that the lifetime of the ISession is the same as the HTTP request. In my opinion, repository classes should never access the SessionFactory and should always have the ISession supplied as a dependency.
精彩评论