Skip to content

VS 2015 compiler fails when providing custom implementation of SqlMapper.enumParse #448

@nCubed

Description

@nCubed

We are using Dapper in a large enterprise winform application. Currently, we are in the process of upgrading our project targets from VS 2013 / .NET 4.5.2 to VS 2015 / .NET 4.6.1.During testing, we found that our Dapper repositories were failing when running under VS 2015.

Specifically, we have unique requirements for handling Enums and have had to take a direct file reference to Dapper which allows us to remove the readonly modifier on the SqlMapper.enumParse field and provide our own implementation which was worked as expected for over a year now.

We've isolated the issue down to what we believe is a difference in the VS 2013 compiler and VS 2015 compiler. Running under VS 2013, there are no issues with providing our own implementation of SqlMapper.enumParse. Under VS 2015, we receive a DataException: "An unhandled exception of type 'System.Data.DataException' occurred..." and the error points to the parsing of the enum.

The following is the bare minimum to reproduce the issue:

  • Set up a solution and target .NET v4.5 to 4.6.1
  • Drop in the code that follows the end of this post.
  • Use the latest Dapper code and remove the SqlMapper.enumParse readonly modifier.

Of Note:

  • The sample code resets the SqlMapper.enumParse field with a different implementation than the native Dapper code which uses the standard .NET Enum.Parse method.
  • The underlying SQL always returns the Product.ProductType as ProductType.Gmo; the implementation of SqlMapper.enumParse will always set the enum to ProductType.Organic.
  • Running under VS 2013, the expected results are produced where the Product.ProductType enum will always be ProductType.Organic. Under VS 2015, an exception occurs.

I realize this is not a Dapper specific issue, but was hoping you could provide some guidance on why this is occuring with the VS 2015 compiler?

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using Dapper;
using DapperRoslyn;

namespace Dapper
{
    static partial class SqlMapper
    {
        internal static void SetEnumParse()
        {
            Func<Type, string, bool, object> dapperEnum = ( type, value, flag ) => ToEnum( type, value );
            enumParse = dapperEnum.Method;
        }

        private static object ToEnum( Type type, string value )
        {
            return ProductType.Organic;
        }
    }
}

namespace DapperRoslyn
{
    class Program
    {
        const string ConnectionString = "Data Source=.;Initial Catalog=.;Integrated Security=True";

        static void Main()
        {
            SqlMapper.SetEnumParse();

            var repo = new ProductRepository( ConnectionString );

            var products = repo.GetAll();

            foreach( Product product in products )
            {
                Console.WriteLine( product );
            }

            Console.ReadLine();
        }
    }

    public class ProductRepository
    {
        private readonly string _connectionString;

        public ProductRepository( string connectionString )
        {
            _connectionString = connectionString;
        }

        public IEnumerable<Product> GetAll()
        {
            const string sql = @"
create table #Product(Name nvarchar(25) not null, ProductType nvarchar(25) not null)

insert into #Product(Name, ProductType)
values
 ('Banana', 'Gmo')
,('Orange', 'Gmo')
,('Pear', 'Gmo')
,('Apple', 'Gmo')
,('Strawberry', 'Gmo')

Select Name, ProductType from #Product

drop table #Product
";

            using( var conn = new SqlConnection( _connectionString ) )
            {
                var results = conn.Query<Product>( sql, commandType: CommandType.Text );

                return results.ToList();
            }
        }
    }

    public enum ProductType
    {
        Unknown = 0,
        Gmo = 1,
        Organic = 2,
    }

    public class Product
    {
        public string Name { get; set; }

        public ProductType ProductType { get; set; }

        public override string ToString()
        {
            return string.Format( "{0} {1}", Name, ProductType );
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions