Bug in SprocAccessor.Execute Enterprise Library 6, DAAB.

Topics: Data Access Application Block
May 15, 2014 at 6:07 PM
Edited May 15, 2014 at 6:16 PM
Hasn't anyone else run into this? The DbCommand object is disposed when trying to access the returned IEnumerable in client code.

The Execute method of the SprocAccessor is returning base.Execute(command):
            using (DbCommand command = Database.GetStoredProcCommand(procedureName))
            {
                parameterMapper.AssignParameters(command, parameterValues);
                return base.Execute(command);
            }
It should do what the SqlStringAccessor does, namely
            foreach (var result in base.Execute(command))
            {
                yield return result;
            }
I changed the SprocAccessor.Execute method to mirror SqlStringAccessor and that fixed it.

How could SprocAccessor ever have worked for anyone?

Mike
May 16, 2014 at 4:41 AM
It seems to be working OK for me. Can you provide a code sample that demonstrates the issue?

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to
May 16, 2014 at 1:51 PM
Edited May 24, 2014 at 12:00 PM
Hi, Randy,

Here's the code. I get "unhandled exception of type "'System.ObjectDisposedException' in IBM.Data.DB2.iSeries.dll. Additional information: Invalid operation. The object has been Disposed." at the "foreach" block. The message property of the exception is: "Invalid operation. The object has been Disposed.
Object name: 'IBM.Data.DB2.iSeries.iDB2Command'."

I should note that I subclassed the Database class for the IBM.Data.DB2.iSeries.dll into an assembly named "iSeriesDatabase". I included the two code files for this. Everything works fine except for the SprocAccessor.

Thank for your help,
Mike

Sample code:
using System;
using System.Collections.Generic;
using Microsoft.Practices.EnterpriseLibrary.Data;

namespace Db2Sample
{
    public class OilProvider
    {
        public string Code { get; set; }
        public string Description { get; set; }
    }

    public class SampleClass
    {
        private static void Main()
        {
            var data = GetOilProviders("iSeries");

            foreach (var p in data)  // EXCEPTION IS THROWN HERE
            {
                Console.WriteLine("{0}  {1}", p.Code.PadRight(20), p.Description);
            }
        }

        public static IEnumerable<OilProvider> GetOilProviders(string databaseName)
        {
            var db = new DatabaseProviderFactory().Create("iSeries");
            var mapper = MapBuilder<OilProvider>.BuildAllProperties();
            var accessor = db.CreateSprocAccessor("PROC_GETOILP", mapper);
            return accessor.Execute();
        }
    }
}
iSeriesDatabase.cs:
using System.Data.Common;
using IBM.Data.DB2.iSeries;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Data;

namespace iSeries.Data
{
    [ConfigurationElementType(typeof (iSeriesDatabaseData))]
    public class iSeriesDatabase : Database
    {
        public iSeriesDatabase(string connectionString)
            : base(connectionString, iDB2Factory.Instance)
        {
        }

        public override bool SupportsParemeterDiscovery
        {
            get
            {
                return true;
            }
        }

        protected override void DeriveParameters(DbCommand discoveryCommand)
        {
            iDB2CommandBuilder.DeriveParameters(discoveryCommand);
        }
    }
}
iSeriesDatabaseData.cs:
using System;
using System.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Data;
using Microsoft.Practices.EnterpriseLibrary.Data.Configuration;

namespace iSeries.Data
{
    public class iSeriesDatabaseData : DatabaseData
    {
        public iSeriesDatabaseData(ConnectionStringSettings connectionStringSettings,
            Func<string, ConfigurationSection> configurationSource)
            : base(connectionStringSettings, configurationSource)
        {
        }

        public override Database BuildDatabase() { return new iSeriesDatabase(ConnectionString); }
    }
}
May 24, 2014 at 5:09 PM
It's interesting that the SqlStringAccessor and the SProcAccessor implementations are different. Not sure why that is. Since it's working OK with SQL Server it makes me wonder what is happening in the DB2 provider.

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to
May 27, 2014 at 2:18 PM
My thought as well.

At this point what are my options? Have my own version of EL6? Can we find out why the SProcAccessor code is different than the SQLStringAccessor code?

Mike
May 28, 2014 at 3:20 AM
I took a closer look and the SqlStringAccessor looks correct whereas the SprocAccessor is not. I'm not sure why they differ.

You are right, the SprocAccessor is disposing the DbCommand object before returning the enumeration. The reason why it works is because for SqlCommand the Dispose method only really sets a metadata cache to null which is not having a functional impact. However, for the DB2Command it looks like it has different logic which is throwing an exception.

In terms of what to do, you could fix it in the source code and run a custom build of Enterprise Library. The Data Access Block is now open source so it's possible to submit the fix and have a new NuGet package released (although I'm not sure what the turnaround time would be). Another alternative would be to create your own accessor that behaves properly (although there are a lot of helper methods to implement if you want to replicate the existing extension methods).

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to
Jun 5, 2014 at 1:46 PM
Hi, Randy.

How would I go about submitting a fix? I've reported this under the "Issues" tab in the DAAB forum several weeks ago but no one responded.

Thanks,

Mike
Jun 5, 2014 at 1:58 PM
See How to Contribute Code. The Data Access Application Block site is located at: http://daab.codeplex.com/ .

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to