Search code examples
.netormenterprise-librarydapper

Add Dapper to Enterprise Library?


We are using the Enterprise Library as a standard DAL. Now, I would like to enjoy the benefits of Dapper. Looking at the implementation it is just extending the connection class.

Is it conceivable to set Dapper to extend Enterprise Library so we can enjoy both worlds? Or maybe someone already created this?


Solution

  • Yes, it is conceivable, and it works pretty well. We're using Dapper to supplement some older EntLib code, and simple queries are quick and painless. The biggest challenge was getting Transactions to work properly. You don't mention which version of EntLib you are using, but 4.0 and newer manage connections inside of TransactionScopes, so if you try to open another connection for Dapper inside of a scope with EntLib it will automatically escalate from a lightweight local transaction to DTC (Distributed Transaction Coordinator). EntLib doesn't really provide a way to grab the current open connection, so you have to derive from the Database class and expose the GetOpenConnection method.

    public class EntLibDatabaseWrapper : Database
    {
        // ...Constructor and overrides...
    
        public IDbConnection GetMyOpenConnection()
        {
            var connectionWrapper = GetOpenConnection();
            return connectionWrapper.Connection;
        }
    }
    

    Then use it something like this:

    var db = DatabaseFactory.CreateDatabase();
    var dbWrapper = new EntLibDatabaseWrapper(db.ConnectionString, db.DbProviderFactory);
    
    using (var scope = new TransactionScope())
    {
        var connection = dbWrapper.GetMyOpenConnection();
    
        try
        {
            // Insert a test value using dapper
            var fooId = 
                connection.Query<int>("insert into Foo values (name = @name); select cast(scope_identity() as int", 
                                        new { name = "Foo" }).Single();
            // Insert a test value using Enterprise Library
            var cmd =
                db.GetSqlStringCommand(
                    "insert into Foo values (name = 'Bar'); select cast(scope_identity() as int)");
            var barId = int.Parse(db.ExecuteScalar(cmd));
            scope.Complete();
        }
        catch (Exception)
        {
            connection.Close();
            throw;
        }
    }
    

    If you have larger transaction scopes then you have to check to see if you are in an active transaction before you close each connection.

    if(Transaction.Current == null)
         connection.Close();