3

I have a situation where a client is requiring that we implement our data access code to use either an Oracle or SQL server database based on a runtime configuration settings. The production environment uses Oracle but both dev and QA are running against a SQL Server instance.

(I don't have any control over this or have any background on why this is the case other than Oracle is their BI platform and dev wants to work with SQL Server.)

Their request is to use LINQ-to-SQL / LINQ-to-Oracle for all data access. They will need to support the application and do not have the knowledge to jump into EF yet (their requirement) - although I believe the same problem exists if we use EF.

While I can implement LINQ to XYZ classes for both databases so that I can connect to both, they don't share a common interface (other than DataContext) so I really can't code against an interface and plug the actual implementation in at runtime.

Any ideas how I should approach this?

UPDATE After writing this post, I did a little investigating into EF and it appears to me that this same problem exists if I use EF - which would be my long term goal.

SonOfPirate
  • 5,642
  • 3
  • 41
  • 97

3 Answers3

0

Just a quick thought. Use MEF framework and plug your DAL layers to it. Then based on the environment(dev, production, QA) you can switch to the various DAL layers(Oracle, SQL etc.).

If you want to know about MEF , here is a quick intro.

Also sometime back I have seen a Generic Data Access Framework by Joydip Kanjilal. You can even have a look into that.

  • Even with MEF, there's no common interface/contract for me to code against. While there's many ways to inject the concrete DAL into the application, all of them, MEF included, require a common contract so that my application can be coded without knowing the concrete implementation. As far as I can tell, when I generate my LINQ-to-SQL classes and then generate a set of LINQ-to-Oracle classes, there is no shared contract (interfaces, base classes, etc) - except DataContext which does me no good since it doesn't have anything to do with the implementation. – SonOfPirate Dec 17 '10 at 03:28
  • You can then refer to a generic data access framework http://www.deitel.com/ResourceCenters/Programming/ADONET/ADONETDataAccessLayer/tabid/3176/Default.aspx –  Dec 17 '10 at 03:31
  • This seems like a major step backwards. I am very familiar with ADO.NET and the implementation of the Abstract Factory pattern that allows us to code independent of the actual provider. However, in reality that only goes so far. There are often times syntax differences between platforms that must be accounted for in our SQL text. This means that we will have different code at some point to accomodate the different syntax requirements. – SonOfPirate Dec 17 '10 at 12:55
0

What you have to do is encapsulate the ORM datacontext in an interface of your creation, like IDataContext.

Then share this interface between all DALs and implement it. How you will plug it in is just your preference, using MEF as suggested or a IoC container.

Matteo Mosca
  • 7,380
  • 4
  • 44
  • 80
0

For the sake of closure on this topic, here is what I ended up doing:

I implemented a combination of the Unit of Work and Repository patterns. The Unit of Work class is what consuming code works with and exposes all of the operations that can be performed on my root entities. There is one UoW per root entity. The UoW makes use of a repository class via an interface. The actual implementation of the repository is dependent on the data access technology being used.

So, for instance, if I have a customer entity and I need to support retrieving and updating each record, I would have something like:

public interface ICustomerManager
{
    ICustomer GetCustomer(Guid customerId);
    void SaveCustomer(ICustomer customer);
}

public class CustomerManager : ICustomerManager
{
    public CustomerManager(ICustomerRepository repository)
    {
        Repository = repository;
    }

    public ICustomerRepository Repository { get; private set; }

    public ICustomer GetCustomer(Guid customerId)
    {
        return Repository.SingleOrDefault(c => c.ID == customerId);
    }

    public void SaveCustomer(ICustomer customer)
    {
        Repository.Save(customer);
    }
}

public interface ICustomerRepository : IQueryable<ICustomer>
{
    void Save(ICustomer customer);
}

I'm using an Inversion of Control framework to inject the ICustomerRepository implementation into the CustomerManager class at runtime. The implementation class will be in a separate assembly that can be swapped out as the data access technology is changed. All we are concerned about is that the repository implements each method using the contract defined above.

As a side note, to do this with Linq-to-SQL, I simply created a LinqCustomerRepository class that implements ICustomerRepository and added a partial class for the generated Customer entity class that implements ICustomer. Then I can return the L2S entity from the repository as the implementation of the ICustomer interface for the UoW and calling code to work with and they'll be none the wiser that the entity originated from L2S code.

SonOfPirate
  • 5,642
  • 3
  • 41
  • 97