What I came up with was something like the following.
SessionProvider.Current would be maintained in
Application_BeginRequest and Application_EndRequest.
At first, I exposed methods like GetAll, Get, Insert,
Update and Delete, but those were kind of restrictive,
so I just made the Session public get.
public interface IUnitOfWork : IDisposable
{
public ISession Session { get; }
public ITransaction Transaction { get; }
}
public class UnitOfWork : IUnitOfWork
{
public ISession Session { get; private set; }
public ITransaction Transaction { get; private set; }
public bool Rollback { get; set; }
public UnitOfWork()
{
Session = SessionProvider.Current;
Transaction = Session.BeginTransaction();
}
public void Dispose()
{
if (Rollback)
Transaction.Rollback();
else
Transaction.Commit();
}
}
public class Test
{
public Test()
{
using (IUnitOfWork worker = new UnitOfWork())
{
// with the Session exposed, I can create custom
criteria if I need to
Category c1 = worker.Session.Get<Category>(1);
Forum f1 = c1.FindForum(x => x.Id == 10);
Category c2 = worker.Session.Get<Category>(2);
c2.AddForum(f1);
worker.Session.Update(c2);
}
}
}
On Aug 16, 6:21 pm, Diego Mijelshon <[email protected]> wrote:
> Are you sure you want to design your desktop application using web patterns?
>
> My suggestion is that you look at the existing solutions for both.
> There are some great examples in uNhAddIns,http://code.google.com/p/unhaddins/
>
> Diego
>
> On Mon, Aug 16, 2010 at 19:10, [email protected] <
>
>
>
> [email protected]> wrote:
> > I'm not convinced that's true, especially when I could just as easily
> > inject the ISession using either a ctor arg (letting the client
> > determine the lifestyle). Though that might get ugly having to add
> > ctors to all my descendants.
>
> > Anyway, on to UnitOfWork. I've been reading up on it while this is all
> > going on, and I think I'm beginning to understand it. You're objection
> > to my repository was that the Insert, Update and Delete methods each
> > used their own transaction. If I based my repository on IDisposable,
> > and added a class level transaction to it, and a bool flag, I could
> > then commit or rollback on disposal. That makes a good deal of sense,
> > but it really wouldn't change the overall code in my action method
> > though. I'd still need to fetch both the current and potential new
> > parent for the forum entity, as well as call update on one or the
> > other.
>
> > With that in mind, wouldn't it be simpler to just do it in the action
> > itself, and scrap the repositories altogether?
>
> > public ActionResult Edit(ForumEditModel model)
> > {
>
> > using (ISession session = SessionProvider.Current)
> > {
> > // do something with session
> > }
>
> > // it makes as much sense as...
>
> > using (IUnitOfWork worker = new UnitOfWork())
> > {
> > // do something with worker.Session
> > }
>
> > }
>
> > Or does an ISession object not dispose itself when used in a using
> > construct?
>
> > On Aug 16, 5:57 pm, Diego Mijelshon <[email protected]> wrote:
> > > Well, that's a problem.
> > > Data access patterns are COMPLETELY DIFFERENT for Web and Desktop
> > > applications.
>
> > > Diego
>
> > > On Mon, Aug 16, 2010 at 18:39, [email protected] <
>
> > > [email protected]> wrote:
> > > > Need to add something....
>
> > > > I can't use HttpContext.Current.Items because this code would make my
> > > > Infrastructure DLL (and the base repository as well) dependant on
> > > > System.Web. It needs to be able to service both web and non-web
> > > > clients (like Winforms).
>
> > > > On Aug 16, 5:35 pm, "[email protected]" <[email protected]>
> > > > wrote:
> > > > > I already use Castle.Windsor for my DI needs, and while I've tried
> > > > > PerWebRequest for my ISession, I've yet to get it working. Tips on
> > > > > that?
>
> > > > > On Aug 16, 5:09 pm, Jason Dentler <[email protected]> wrote:
>
> > > > > > Problem #1: You must close / dispose the session. Period. No
> > > > exceptions. If
> > > > > > not, you will eat up all available database connections and crash.
>
> > > > > > You should use session-per-request. There's a couple of ways to
> > handle
> > > > this.
> > > > > > The best way, IMO, is to use a dependency injection framework like
> > > > Ninject,
> > > > > > Windsor, or StructureMap.
>
> > > > > > If you don't understand dependency injection, put it on your list
> > of
> > > > things
> > > > > > to learn by the end of the week, and then do this: Call
> > > > > > sessionFactory.OpenSession() when the request starts, and
> > > > session.Dispose()
> > > > > > when the request ends. Store the session in HttpContext.items.
>
> > > > > > You can also open and close the session with an MVC action filter.
>
> > > > > > Problem #2: Don't do the micro-transaction anti-pattern. You're
> > opening
> > > > and
> > > > > > closing transactions with every little call in to your repository.
> > > > > > Transactions should surround the entire business transaction. I
> > like to
> > > > use
> > > > > > an action filter for this, but there's a number of ways to do it.
>
> > > > > > On Mon, Aug 16, 2010 at 11:47 AM, [email protected] <
>
> > > > > > [email protected]> wrote:
> > > > > > > It's an asp.net mvc app. Base repository is a generic in my
> > > > > > > infrastrature dll, implementations are in persistence dll, and
> > the
> > > > > > > "unit of work" as you call it, is in the httppost handler action
> > for
> > > > > > > Forum/Edit/{id}. The configuration and session factory are
> > > > initialized
> > > > > > > in the application start event in Global.asax via a little static
> > > > > > > utility class I wrote. Each repository asks that class for a
> > session
> > > > > > > (one per instantiation). Disposing? Not really doing that.. It
> > was
> > > > not
> > > > > > > in any of the tutorials. I guess I could do it in a
> > deconstructor.
> > > > How
> > > > > > > would that help? The incoming viewmodel has a category id,
> > grabbed
> > > > > > > from a dropdown list. Basically I do this:
>
> > > > > > > public actionresult Edit(ForumEditModel model)
> > > > > > > {
>
> > > > > > > Category current =
> > categoryRepository.SelectFromForumId(model.Id);
> > > > > > > Forum forum = current.GetForumById(model.Id);
>
> > > > > > > // update forum properties and then
>
> > > > > > > Categoru destination =
> > > > > > > categoryRepository.SelectById(model.CategoryId);
>
> > > > > > > if (current != destination)
> > > > > > > {
> > > > > > > destination.AddForum(forum);
> > > > > > > categoryRepository.Update(destination);
> > > > > > > }
> > > > > > > else
> > > > > > > {
> > > > > > > categoryRepository.Update(current)
> > > > > > > }
> > > > > > > }
>
> > > > > > > It works accept for that masty refreshing thing.
>
> > > > > > > Now then, ,what are you suggestions at this point regarding unit
> > of
> > > > > > > work?
>
> > > > > > > On Aug 16, 12:31 pm, Jason Dentler <[email protected]>
> > wrote:
> > > > > > > > Yes. You have some strange ideas about unit of work. Let's
> > start
> > > > with the
> > > > > > > > basics and work up from there. What type of application is this
> > -
> > > > web,
> > > > > > > wpf,
> > > > > > > > wcf? Where are you starting the session? Where are you
> > disposing
> > > > it?
>
> > > > > > > > On Mon, Aug 16, 2010 at 9:54 AM, [email protected] <
>
> > > > > > > > [email protected]> wrote:
> > > > > > > > > Well, I'm at college at the moment, so I do not have the
> > exact
> > > > code, I
> > > > > > > > > will post that when I get home,
>
> > > > > > > > > In the meantime, here is what I can tell you.
>
> > > > > > > > > public void Update(T entity)
> > > > > > > > > {
>
> > > > > > > > > using (ITransaction tx = Session,BeginTransaction())
> > > > > > > > > {
> > > > > > > > > Session.Update(entity);
> > > > > > > > > tx.Commit();
>
> > > > > > > > > // see comment below on this line
> > > > > > > > > Session.Clear();
>
> > > > > > > > > }
>
> > > > > > > > > }
>
> > > > > > > > > ** I got the following code to work, but it requires the
> > > > commented
> > > > > > > > > line above so that subsequent selects do not show the entity
> > as
> > > > being
> > > > > > > > > owned by two separate parents because of the NH caching. The
> > db
> > > > > > > > > changes work.
>
> > > > > > > > > if (currentCategory != destinationCategory)
> > > > > > > > > {
> > > > > > > > > destinationCategory.AddForum(forum);
> > > > > > > > > categoryRepository.Updaet(destination);
> > > > > > > > > }
>
> > > > > > > > > So let ne refine my original question to this instead: is
> > there a
> > > > > > > > > better way of refreshing things other than calling Clear()?
>
> > > > > > > > > On Aug 16, 8:40 am, Jason Dentler <[email protected]>
> > > > wrote:
> > > > > > > > > > You need to perform the operation as a single unit of work.
> > > > Don't
> > > > > > > flush
> > > > > > > > > the
> > > > > > > > > > session after each little piece.
>
> > > > > > > > > > For the future, we really need to see your NH code, not
> > your
> > > > > > > repository
> > > > > > > > > > abstraction on top of NH.
>
> > > > > > > > > > On Sun, Aug 15, 2010 at 11:06 PM, [email protected] <
>
> > > > > > > > > > [email protected]> wrote:
> > > > > > > > > > > I have a relatively simple application where my main
> > > > aggregate
> > > > > > > chain
> > > > > > > > > > > is: Category -> Forum -> Thread -> Reply.
>
> > > > > > > > > > > My aggregate root repository is CategoryRepository
> > natually.
>
> > > > > > > > > > > I have AllDeleteOrphan set in my HasManyConvention so I
> > can
> > > > perform
> > > > > > > > > > > deletes like the following.
>
> > > > > > > > > > > category.RemoveForum(forum);
> > > > > > > > > > > categoryRepository.Update(category);
>
> > > > > > > > > > > Without it, all that happens is the foreign key get's
> > nulled
> > > > out,
> > > > > > > but
> > > > > > > > > > > the record remains. With it set, it works like it should.
> > > > However,
> > > > > > > it
> > > > > > > > > > > introduces a problem in another action where I need to
> > move a
> > > > forum
> > > > > > > to
> > > > > > > > > > > another category. This code will demonstrate.
>
> > > > > > > > > > > if (currentCategory != destinationCategory)
> > > > > > > > > > > {
>
> > > > > > > > > > > // this seems to be needed so that the cache doesn't show
> > the
> > > > forum
> > > > > > > in
> > > > > > > > > > > both categories
> > > > > > > > > > > currentCategory.RemoveForum(forum);
>
> > > > > > > > > > > // THIS LINE CAUSES THE ERROR. by the time it completes,
> > the
> > > > forum
> > > > > > > is
> > > > > > > > > > > an orphan and is deleted.
> > > > > > > > > > > categoryRepository.Update(currentCategory);
>
> > > > > > > > > > > // now add it to the destination
> > > > > > > > > > > destinationCategory.AddForum(forum);
>
> > > > > > > > > > > // and save it
> > > > > > > > > > > categoryRepository.Update(destinationCategory);
>
> > > > > > > > > > > }
>
> > > > > > > > > > > So the question is: what is the proper way to perform
> > this
> > > > > > > operation?
>
> > > > > > > > > > > --
> > > > > > > > > > > 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
>
> ...
>
> read more »- Hide quoted text -
>
> - Show quoted text -
--
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.