No Way to Pass Enumerated Types to Underlying Implementation
Nobody has claimed this yet.
- Dominant language
- C#
- Stars
- 18.4k
- Forks
- 3.7k
- Avg merge
- 5h 8m
- Merged PRs (30d)
- 1
Description
With the latest release of Npgsql (v3), enumerations should be passed as the enumerated type (not the underlying integral type). Unfortunately, the only way to do this using Dapper (v1.42) is by wrapping every enumeration parameter in an SqlMapper.ICustomQueryParameter class (cannot add a type handler due to issues #259 and #286). Even if those issues are resolved, it would be nice if there was some setting that enabled Dapper to bypass the if (type.IsEnum() && !typeMap.ContainsKey(type)) portion of SqlMapper.LookupDbType, as well as the if (value is Enum) portion of SqlMapper.SanitizeParameterValue. Then, passing enumerated values as parameters would work with Npgsql without issue. For example, here is the existing code for LookupDbType and SanitizeParameterValue in SqlMapper.cs:
internal static DbType LookupDbType(Type type,
string name, bool demand, out ITypeHandler handler)
{
DbType dbType;
handler = null;
var nullUnderlyingType = Nullable.GetUnderlyingType(type);
if (nullUnderlyingType != null) type = nullUnderlyingType;
if (type.IsEnum() && !typeMap.ContainsKey(type))
{
type = Enum.GetUnderlyingType(type);
}
if (typeMap.TryGetValue(type, out dbType))
{
return dbType;
}
if (type.FullName == LinqBinary)
{
return DbType.Binary;
}
if (typeHandlers.TryGetValue(type, out handler))
{
return DbType.Object;
}
if (typeof(IEnumerable).IsAssignableFrom(type))
{
return DynamicParameters.EnumerableMultiParameter;
}
#if !DNXCORE50
switch (type.FullName)
{
case "Microsoft.SqlServer.Types.SqlGeography":
AddTypeHandler(type, handler = new UdtTypeHandler("geography"));
return DbType.Object;
case "Microsoft.SqlServer.Types.SqlGeometry":
AddTypeHandler(type, handler = new UdtTypeHandler("geometry"));
return DbType.Object;
case "Microsoft.SqlServer.Types.SqlHierarchyId":
AddTypeHandler(type, handler = new UdtTypeHandler("hierarchyid"));
return DbType.Object;
}
#endif
if (demand)
throw new NotSupportedException(string.Format(
"The member {0} of type {1} cannot be used as a parameter value",
name, type.FullName));
return DbType.Object;
}
internal static object SanitizeParameterValue(object value)
{
if (value == null) return DBNull.Value;
if (value is Enum)
{
TypeCode typeCode;
if (value is IConvertible)
{
typeCode = ((IConvertible)value).GetTypeCode();
}
else
{
typeCode = TypeExtensions.GetTypeCode(Enum.GetUnderlyingType(value.GetType()));
}
switch (typeCode)
{
case TypeCode.Byte: return (byte)value;
case TypeCode.SByte: return (sbyte)value;
case TypeCode.Int16: return (short)value;
case TypeCode.Int32: return (int)value;
case TypeCode.Int64: return (long)value;
case TypeCode.UInt16: return (ushort)value;
case TypeCode.UInt32: return (uint)value;
case TypeCode.UInt64: return (ulong)value;
}
}
return value;
}
My proposal is to add the following to SqlMapper.cs:
// The default is to convert enumerated values to the underlying type,
// to prevent breaking existing code
public static bool SanitizeEnumValues = true;
And to modify the following conditional in SqlMapper.LookupDbType:
// Existing conditional
if (type.IsEnum() && !typeMap.ContainsKey(type))
// Proposed change
if (SanitizeEnumValues && type.IsEnum() && !typeMap.ContainsKey(type))
And to modify the following conditional in SqlMapper.SanitizeParameterValue:
// Existing conditional
if (value is Enum)
// Proposed change
if (SanitizeEnumValues && value is Enum)
I think such a change is of minimal risk, since the default behavior is to do exactly what Dapper does now. However, this would enable me to gracefully work with Npgsql enumeration support.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in SqlMapper.cs with LookupDbType and SanitizeParameterValue, using the proposed SanitizeEnumValues setting and the existing enum branches as the scope. Verify that the default preserves current enum conversion while disabling it permits enumerated parameters for Npgsql; completion should cover both code paths and their compatibility behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- backend, databases
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 35/100