1. you will need a reference to the session factory (static gateway
maybe) on you have that, you can call
SessionFactory.GetCurrentSessionContext(); to get the session. you
want a singleton of session factory in your application anyway. an IoC
is not required, but I find it' like accessing a database without NH.
I can, but I don't like to.
2. I found this to be a paradigm shift in my thinking when i first
moved from gui-domain-database to gui-view model-domain model-
database. in a simple application where your business domain maps 1:1
with the view model it can seem redundant to have the 2 separate
models. in recent projects I have come to embrace the distinction
between the view model and domain model (AutoMapper makes the
conversion from domain to view almost mindless). reasons for this:
1. I can build my gui independent of the domain
2. my view model can be DTOs while my domain can have rich/
complex logic.
3. my view doesn't need to look like the domain and the domain
doesn't need to look like the view.
you also mentioned a client/server enviornment where all db work is
done on the server and you are using remoting between the client and
server. this is another layer of complexity and I would definately go
the route of DTO over the wire.
knowing now about the client/server and remoting architecture, I
wouldn't use a request/response model. I would use a publish/
subscribe. This is more complex, but it's becomes easier to manage the
asynchronous nature. it will also keep the GUI responsive as all
remote calls are pushed to the background on the client, not the
server.
On Nov 11, 12:30 am, mt <[email protected]> wrote:
> Jason,
>
> Thank you again for such a detailed response. Slowly, I am beginning
> to understand your suggested solution and the negatives in the
> direction I was heading. I think I can implement very close to you
> have above only difference is that the UI will not be directly updated
> when the SynchronizationContext moves the data to the main thread.
> The main thread is a service layer which clients connect to via .NET
> remoting. So at a high level the architecture is 1 or more clients
> call a remote service to save/retrieve data. The remote service sends
> the data request to the database using the CLR threadpool and
> NHibernate. Data is sent back to the service layer who sends it back
> to the requesting client via .NET remoting again. But I do have a few
> questions
>
> 1. I think your IoC container is setting the session in the service
> to session.GetCurrentSession. Due to reasons out of my control and
> the ramp up time it would take to learn and shift the application to
> use IoC, I cannot implement that now. Perhaps the next iteration...
> Where would I set the session to GetCurrentSession if I am not using
> an IoC? Would there be other major changes to your approach if you
> could not use an IoC.
>
> 2. Currently our application has domain objects which contain a
> considerable amount of business logic. A property of each domain
> object is a dumb POCO dto which is automapped using Fluent and gets
> sent to the database and back. It seems unnecessary overhead to
> completely separate out the dtos from the domain objects and have a
> mapping layer to and from each domain and dto. If I close the
> nhibernate session after a database call then the entity is no longer
> attached to a session and can be safely sent back to the main thread
> where the domain entity is updated with the updated dto property.
> What are your thoughts on this?
>
> 3.
>
> On Nov 10, 4:29 pm, Jason Meckley <[email protected]> wrote:
>
> > you do not need a singleton to move data between threads. consider the
> > AsyncExecutor in the code sample. the SynchronizationContext is
> > handling moving the data from the background to the UI thread.
>
> > I would not transmit the domain entities across threads either,
> > session is not thread safe, and moving a persisted object across
> > threads will cause cross threaded sessions. Once you are ready to
> > leave a thread I would transmit a DTO specific to the portion of the
> > UI you are updating. you will have many small objects. but each
> > objects has 1 purpose.
>
> > The code is complex, but so is threading. There is no way around that.
> > the code I provided is the complex part, and it's encapsulated. once
> > it's in place your code looks like the presenter and you are not
> > bothered with the details of the ICommandExecutor implementations.
>
> > reviewing your DAO object. the MakePersistent is the worst way you can
> > use NH.
> > 1. you will end up writing most of the code multiple times. open
> > session, begin transaction, commit, close.
> > 2. you are not disposing of the transaction or session. and they are
> > not within a try/finally block. if an exception is thrown you will
> > have orphaned sessions.
> > 3. you loose all the benefits on what ISession provides, identity map,
> > unit of work, etc.
> > 4. there is no need for an explicit call to save or update. the
> > session will handle this for you, once the entity is associated to the
> > session.
>
> > the main difference I see between our approaches is where we define
> > the UOW boundaries. you approach makes every call to the db it's own
> > UOW. I define my UOW in the context of what the presenter requires.
>
> > I would also recommend implementing an IoC, even for small/simple
> > applications they make infrastructure so much easier. Of course, if
> > you have not used one before, they can appear daunting.
>
> > On Nov 10, 5:01 pm, mt <[email protected]> wrote:
>
> > > Jason thanks for the detailed answer. Your answer led me to discover
> > > fluent nhibernate which we now adopted. However, your code seems
> > > overly complex for my situation. I dont have an IoC container that I
> > > am using at all. I am trying to extract from your sample code what I
> > > would need to do:
>
> > > Essentially in the callback function i would:
> > > 1. open new session
> > > 2. begin transaction
> > > 3. perform database operation (save or retrieve)
> > > 4. end trnsaction
> > > 5. close session
> > > 6. I am thinking the only way to update the main thread is to send
> > > the saved or retrieved entity to a singleton object.
>
> > > Does this make sense or am I still missing something?
>
> > > below is some psudo-code.
>
> > > //business layer
> > > widgetDao.Save(widget)
> > > .
> > > .
> > > .
> > > //called by business layer
> > > public T Save (T entity)
> > > {
> > > WaitCallback workItem = new WaitCallback
> > > (MakePersistent,entity);
> > > ThreadPool.QueueUserWorkItem(workItem);
> > > }
> > > //called by thread from threadpool
> > > protected Object MakePersistent(Object entity){
> > > session = NHibernateHelper.OpenSession();
> > > session.beginTransaction()
> > > T entity = session.SaveOrUpdate(entity);
> > > session.endTransaction();
> > > session.CloseSession() ;
> > > //give back to main thread through a singleton object
> > > Singleton.getInstance.entityList.Add(entity);
> > > }
>
> > > On Nov 6, 1:28 pm, Fabio Maulo <[email protected]> wrote:
>
> > > > Thanks... another man with good karma!
>
> > > > 2009/11/6 Jason Meckley <[email protected]>
>
> > > > > the wiki how-to is posted. I refactored a bit, but the intent is still
> > > > > the same.
>
> > > > >http://nhforge.org/wikis/howtonh/currentsessioncontext-for-desktop-de...
>
> > > > > On Nov 6, 11:57 am, Fabio Maulo <[email protected]> wrote:
> > > > > > Hi Jason.
> > > > > > Would be nice a blog-post or an how-to wiki.
> > > > >http://nhforge.org/wikis/howtonh/default.aspx
>
> > > > > > 2009/11/6 Jason Meckley <[email protected]>
>
> > > > > > > I have used something similar with Service Buses and Web
> > > > > > > applications.
> > > > > > > really the only difference between the web and thread is how to
> > > > > > > hook
> > > > > > > in. with web is begin/end request, which has easy hooks to tie
> > > > > > > into.
> > > > > > > with a thread is the start/close of a new thread. the hooks do not
> > > > > > > exist, so you need to provide them yourself.
>
> > > > > > > I use the GetCurrentSession with all my NH projects. if you have a
> > > > > > > single NH factory then ThreadStaticCurrentSessionContext is the
> > > > > > > way to
> > > > > > > go. Then you start work on the new thread open a session and
> > > > > > > bind to
> > > > > > > the current session context. you can then get the current session
> > > > > > > from
> > > > > > > the current factory. when the thread is closed (or about to close)
> > > > > > > dispose of the session (commit transaction).
>
> > > > > > > I use this approach in conjunction with TransactionScope to
> > > > > > > manage the
> > > > > > > transaction.
> > > > > > > ok, so what does this look like? web is explained numerous times
> > > > > > > on
> > > > > > > the net. it doesn't sound like you are using a service bus to
> > > > > > > handle
> > > > > > > the threadings/async. if you are the bus should have hooks for
> > > > > > > recieve/
> > > > > > > complete consuming a message. this is the place to start/end the
> > > > > > > session and transaction.
>
> > > > > > > if you are using straight threading I would use this approach.
> > > > > > > 1. have a single object which manages the threading and context
> > > > > > > synchronization.
> > > > > > > 2. use this object as the place to manage your Nh scope.
>
> > > > > > > building off of Jeremy Miller's latest MSDN article of everyday
> > > > > > > functional programming in .net we will use an Executor object to
> > > > > > > manage the threading. as we off load the work to the the thread
> > > > > > > we can
> > > > > > > open/close our session.
>
> > > > > > > public interface ICommandExecutor
> > > > > > > {
> > > > > > > void Execute(Action action);
> > > > > > > void Execute(Func<Action> action);
> > > > > > > }
>
> > > > > > > public class AsynchronousExecutor : ICommandExecutor
> > > > > > > {
> > > > > > > private readonly SynchronizationContext synchronizationContext;
> > > > > > > private readonly ISessionFactory factory;
>
> > > > > > > public AsynchronousExecutor(ISessionFactory factory,
> > > > > > > SynchronizationContext synchronizationContext)
> > > > > > > {
> > > > > > > this.synchronizationContext = synchronizationContext;
> > > > > > > this.factory = factory;
> > > > > > > }
>
> > > > > > > //useful for operations that will not have an impact on the
> > > > > > > GUI.
> > > > > > > one-way operations
> > > > > > > public void Execute(Action action)
> > > > > > > {
> > > > > > > ThreadPool.QueueUserWorkItem(item =>
> > > > > > > {
> > > > > > > using(var transaction = new
> > > > > > > TransactionScope
> > > > > > > ())
> > > > > > > using(var session = factory.OpenSession())
> > > > > > > {
> > > > > > > CallSessionContext.Bind(factory,
> > > > > > > session);
> > > > > > > action();
> > > > > > > transaction.Complete();
> > > > > > > CallSessionContext.Unbind(factory);
> > > > > > > }
> > > > > > > });
> > > > > > > }
>
> > > > > > > //do the bulk of the work in the background, then marshal the
> > > > > > > result back to the UI thread.
> > > > > > > public void
>
> ...
>
> read more »
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"nhusers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/nhusers?hl=en
-~----------~----~----~----~------~----~------~--~---