Getting NCommon to work with LinqToSql

79 views
Skip to first unread message

Davo

unread,
Feb 10, 2010, 6:44:49 PM2/10/10
to ncommon
I found NCommon whilst researching DDD and the Repository pattern and
love the full implementation of Repository, Specification and Unit of
Work patterns.

I have downloaded any samples of usage that I can find but there does
not appear to be a working sample of the LinqToSql other then unit
tests using Mock's.

I have not been able to get LinqToSql working, I am using Windsor
Container, which I am also new too. Here is my code.

Register the interfaces that I believe I need:

IWindsorContainer container = new WindsorContainer();
container.Register(Component.For(typeof(IRepository<>)).ImplementedBy(typeof(LinqToSqlRepository<>)).LifeStyle.Is(LifestyleType.Transient));

container.Register(Component.For<ITransaction>().ImplementedBy<LinqToSqlTransaction>().LifeStyle.Is(LifestyleType.Transient));

container.Register(Component.For<IUnitOfWork>().ImplementedBy<LinqToSqlUnitOfWork>().LifeStyle.Is(LifestyleType.Transient));

container.Register(Component.For<IUnitOfWorkFactory>().ImplementedBy<LinqToSqlUnitOfWorkFactory>().LifeStyle.Is(LifestyleType.Transient));

container.Register(Component.For<IQuoteRequestRepository>().ImplementedBy<QuoteRequestRepositoryInLinq>().LifeStyle.Is(LifestyleType.Transient));

LinqToSqlUnitOfWorkFactory.SetDataContextProvider(() =>
{
var context = new CarInsuranceDataContext
{ DeferredLoadingEnabled = true };
return context;
});

My Repository
public class QuoteRequestRepositoryInLinq :
LinqToSqlRepository<QuoteRequest>, IQuoteRequestRepository
{
}

Try to get a Repository
using (IocUtil.GetInstance<IUnitOfWork>())
{
var respository =
IocUtil.GetInstance<IQuoteRequestRepository>();

foreach (var item in respository)
{
_.Print(item.ToEntityString(0, " "));
}
}


Exception
CarInsurance.Test.QuickTest.ShouldResolveRequestedTypeFromUnderlyingContainer:
Microsoft.Practices.ServiceLocation.ActivationException : Activation
error occured while trying to get instance of type IUnitOfWork, key ""
----> Castle.MicroKernel.Handlers.HandlerException : Can't create
component 'NCommon.Data.LinqToSql.LinqToSqlUnitOfWork' as it has
dependencies to be satisfied.
NCommon.Data.LinqToSql.LinqToSqlUnitOfWork is waiting for the
following dependencies:

Services:
- NCommon.Data.LinqToSql.ILinqSession which was not registered.


I cannot register ILinqSession because it the implementation is
internal.

We are starting the project this week so I hope someone can help.

Cheers Dave

Ritesh Rao

unread,
Feb 11, 2010, 11:18:27 AM2/11/10
to nco...@googlegroups.com
Hi Dave,

The problem here seems to be that you are trying to get an instance of IUnitOfWork directly from the container. When using this approach, you'd need also register your own implementation of ILinqSession that wraps the L2S DataContext that will be used by the IUnitOfWork implementation. The same pattern applies for all unit of work implementations, NHibernate, EF and L2S. The only reason LinqToSQLUnitOfWork depends on the ILinqSession is because it is very hard mock out DataContext instances when testing (and the same pattern is applied to EFUnitOfWork as well, it depends on a IEFSession interface).

Normally you would not resolve a IUnitOfWork instance from the container, instead use UnitOfWork.Create() method to create and initialize a unit of work. The static UnitOfWork.Create method uses the service locator to resolve the underlying IUnitOfWorkFactory instance and call it's Create method to create and initialize an instance of IUnitOfWork. The LinqToSqlUnitOfWorkFactory internally will create a an instance of LinqToSqlSession and pass in the DataContext you specify via SetDataContextProvider() method. 

Alternatively you could also use the UnitOfWorkScope to manage your unit of work. Below are examples of both approaches:

Using UnitOfWork.Create()

 using (var unitofWork = UnitOfWork.Create())

           {
               var respository = IocUtil.GetInstance<IQuoteRequestRepository>();

               foreach (var item in respository)
               {
                   _.Print(item.ToEntityString(0, "    "));
               }
           }

Using UnitOfWorkScope
using (var scope = new UnitOfWorkScope())

{
               var respository = IocUtil.GetInstance<IQuoteRequestRepository>();

               foreach (var item in respository)
               {
                   _.Print(item.ToEntityString(0, "    "));
               }
     scope.Commit();
}

Let me know if that helps or if you have any additional questions.

Thanks,
Ritesh Rao


--
You received this message because you are subscribed to the Google Groups "ncommon" group.
To post to this group, send email to nco...@googlegroups.com.
To unsubscribe from this group, send email to ncommon+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/ncommon?hl=en.


Davo

unread,
Feb 11, 2010, 10:20:52 PM2/11/10
to ncommon
Hi Ritesh,

I had some issues getting things to work and would just like to go
over them.

1. What is the conceptual difference between UnitOfWork and
UnitOfWorkScope ?

2. The example you give for UnitOfWork.Create does not work because
there is no factory method called Create on this class, I tried
following code but it failed.

using ((new LinqToSqlUnitOfWorkFactory()).Create())
{
//var respository =
IocUtil.GetInstance<IQuoteRequestRepository>();
var respository = new
LinqToSqlRepository<QuoteRequest>();

foreach (var item in respository)
{

_.P(item.ToEntityString(0, " "));
}
}

System.InvalidOperationException : No compatible UnitOfWork instance
was found. Please start a compatible unit of work before creating the
repository or use the constructor overload to explicitly provide a
ObjectContext.


I'm wondering still what the best pattern is to use with LinqToSql.

Do you have a sample application that uses LinqToSql with Windsor, I
know you have one for entity framework.

Cheers Dave

Davo

unread,
Feb 11, 2010, 11:39:59 PM2/11/10
to ncommon
UnitOfWorkScope,

Do you need to do a scope.Commit for queries, code seams to work if I
comment out the Commit but I was wondering if they were implications
of not committing.

using (var scope = new UnitOfWorkScope())
{
var respository =

Ioc.GetInstance<IQuoteRequestRepository>();

foreach (var item in respository)
{

_.P(item.ToEntityString(0, " "));
}
//scope.Commit();
}

Dave

Ritesh Rao

unread,
Feb 12, 2010, 10:00:32 AM2/12/10
to nco...@googlegroups.com
Hi Dave,

Please see my comments inline:

On Thu, Feb 11, 2010 at 10:20 PM, Davo <davo.net@gmail.com> wrote:
Hi Ritesh,

I had some issues getting things to work and would just like to go
over them.

1. What is the conceptual difference between UnitOfWork and
UnitOfWorkScope ?

The conceptual difference between the two is expicit vs implicit transactional management of unit of works. When managing UnitOfWorks manually using the UnitOfWork class your data access components need to manage the transactional state of the unit of work. You can think of UnitOfWorkScope analogous to TrasactionalScope in .Net. A UnitOfWorkScope represents a unit of work transactional scope that can be shared between multiple components. The commit or rollback state of a UnitOfWorkScope is based on all the participating UnitOfWorkScopes. Lets take the example below:

using (var scopeA = new UnitOfWorkScope())
{
    //Do something here.
    CallB();
    //Do something else here.
    scopeA.Commit();
}
 
void B()
{
   using (var scopeB = new UnitOfWorkScope())
   {
       //Do Something Here
       scopeB.Commit();
   }
}

In the above example, scopeA will not commit as long as scopeB has not notified that it has comitted. Similarly, scopeB's actions will not be comitted if scopeA is rolledback.

You can take a look at this blog post for more details on the difference between the two: http://www.codeinsanity.com/2008/10/unit-of-work-pattern-part-deux.html


2. The example you give for UnitOfWork.Create does not work because
there is no factory method called Create on this class, I tried
following code but it failed.

using ((new LinqToSqlUnitOfWorkFactory()).Create())
           {
               //var respository =
IocUtil.GetInstance<IQuoteRequestRepository>();
               var respository = new
LinqToSqlRepository<QuoteRequest>();

               foreach (var item in respository)
               {
                   _.P(item.ToEntityString(0, "    "));
               }
           }

System.InvalidOperationException : No compatible UnitOfWork instance
was found. Please start a compatible unit of work before creating the
repository or use the constructor overload to explicitly provide a
ObjectContext.

I apologize, it should be UnitOfWork.Start(). You can start the unit of work manually using the Start() method. 
 

I'm wondering still what the best pattern is to use with LinqToSql.

Do you have a sample application that uses LinqToSql with Windsor, I
know you have one for entity framework.

Sample apps is the one area I need to work on. I'll see if I can hook something up quick and dirty for you soon. In the meantime if your running into roadblocks feel free to ping me via google talk (rao dot ritesh at gmail.com) and I'd be glad to help.

Ritesh Rao

unread,
Feb 12, 2010, 10:16:10 AM2/12/10
to nco...@googlegroups.com
Technically you don't "need" to scope.Commit() in read operations [the scope will rollback if its not committed during dispose], BUT it's generally good practice to do so. Alternatively you can start scopes using auto complete mode. This will instruct to commit the underlying transaction automatically, or rollback of the commit failed. 

I would advice to use AutoComplete only when you have pure data access scopes, i.e. All you do within the scope is work on repositories. If code within a scope performs custom business logic / calls other components id recommend explicitly calling scope.Commit() at the end of the scope.

You can start scopes in AutoComplete mode like so:

using (new UnitOfWorkScope(UnitOfWorkScopeTransactionOptions.AutoComplete))
{
}

Hope this helps.

- Ritesh Rao


Dave

Reply all
Reply to author
Forward
0 new messages