views:

81

answers:

2

Hi everybody! I think i have some design errors in my ongoing web project (i'm using Linq2SQL implementing repository pattern) 1) Every repository creates its own DataContext (is this correct?should this be this way) For example:

public class SQLPersonRepository : IPersonRepository
{
    DataContext dc;

    public SQLPersonRepository(string connectionString)
    {

        dc = new DataContext(connectionString, Mapping.GetMapping());

        personTable = (dc).GetTable<Person>();
        personRoleTable = (dc).GetTable<PersonRole>();
        roleTable = (dc).GetTable<Role>();

    }
  Get Method 
 Add Methods for the different Tables
 Save Method
}

and another example:

class SQLTrainingCenterRepository:ITrainingCenterRepository
    {
        DataContext dc;
        private Table<Trainingcenter> trainingCenterTable;

    public SQLTrainingCenterRepository(string connectionString)
        {            
            dc = new DataContext(connectionString, Mapping.GetMapping());

            trainingCenterTable = (dc).GetTable<Trainingcenter>();            
        } 

     Get Methods
     Add Method
     Save Method        
}

As you can figure out i'm using IoC (Windsor, using lifestyle="PerWebRequest").

2) Using a services layer for every repository. E.g. for persons

public class PersonBusinessLayer
{
    IPersonRepository personRepository;

    public PersonBusinessLayer(IPersonRepository personRepository)
    {
        this.personRepository = personRepository;

    }
  ...  diverse Get Methods
 Add Method   (wrapper around repository.Add)
 Save Method  (wrapper around repository.Save)
}

Is this the correct way of defining a services layer? Or should i use one service class which references all the repositories?

3) There is a relation between personTable and trainingCenterTable. Every time i insert something into the TrainingCenter-Service i must also insert one record into the Person-Service. So the solution to this is to say :

TrainingCenterBusinessLayer.Insert(trainingCenter);
PersonBusinessLayer.Insert(person);

Of course i want these two insertions happening in Transactional manner, so i decide to wrap this statements in

using (TransactionScope scope = new TransactionScope())
{
...
}

So there arises a new problem: MSDTC on server '.\SQLEXPRESS' is unavailable(because there are different DataContexts,right??). How to overcome this?!?

A solution would be to create the DataContext externally and pass it as a parameter to the repository!?? Correct thinking? But how to implement?

4)With the existing design i have to call: TrainingCenterBusinessLayer.Save(); PersonBusinessLayer.Save(); i think this is wrong! The save() operation should be called once in the DataContext. But how? (apparently this can be solved if the above point is solved).

+1  A: 

I was having a similar issue to yourself. The way I solved it was by passing a DataContext into my repositories. I then used StructureMap to create one instance of the DataContext per web request.

You may find the following posts interesting:

http://stackoverflow.com/questions/1591822/linq-to-sql-multiple-data-context-in-same-transaction

http://www.west-wind.com/weblog/posts/246222.aspx

http://blog.codeville.net/2007/11/29/linq-to-sql-the-multi-tier-story/

vakman
A: 

If you're doing full-on DI, you should try to pass around an abstraction (interface) as the dependency. That way, if you want to mock it, you can easily swap out its implementation.

DataContext is OK to pass around, but perhaps a bit heavy. A better choice IMO would be IDbConnection.

A connection string is not really a dependency, it's a parameter used to initialize a specific implementation of a dependency.

There's also the MvcFakes approach with IDataContext and context wrapper, but I find that to be a pain. As long as your DataContext instances share the same connection instance, you won't need a distributed transaction.

Aaronaught