Skip to content

Commit

Permalink
Merge pull request #44 from Havagan/feature/convert-int-long
Browse files Browse the repository at this point in the history
Refactored the OracleValueConverter to support Get<int> and Get<long>.
  • Loading branch information
epaulsen authored Aug 4, 2020
2 parents 7ead95f + 6b5ef09 commit a92447a
Show file tree
Hide file tree
Showing 8 changed files with 220 additions and 64 deletions.
4 changes: 2 additions & 2 deletions src/Dapper.Oracle.StrongName/Dapper.Oracle.StrongName.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<Import Project="..\common.targets"/>
<PropertyGroup>
<IsTestProject>false</IsTestProject>
<TargetFrameworks>netstandard2.0;net452</TargetFrameworks>
<TargetFrameworks>netstandard2.0;net461</TargetFrameworks>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
Expand All @@ -24,6 +24,6 @@
<PackageReference Include="Dapper.StrongName" Version="1.50.2"/>
</ItemGroup>
<PropertyGroup Condition=" $(IsNetFramework) ">
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
</PropertyGroup>
</Project>
7 changes: 4 additions & 3 deletions src/Dapper.Oracle/Dapper.Oracle.StrongName.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,22 @@
<Import Project="..\common.targets" />
<PropertyGroup>
<IsTestProject>false</IsTestProject>
<TargetFrameworks>netstandard2.0;net452</TargetFrameworks>
<TargetFrameworks>netstandard2.0;net461</TargetFrameworks>
</PropertyGroup>

<ItemGroup Condition=" $(IsNetFramework) ">
<Reference Include="Microsoft.CSharp" />
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Data" />
<Reference Include="System.Runtime.Serialization" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Dapper" Version="1.50.2" />
<PackageReference Include="Dapper" Version="2.0.35" />
</ItemGroup>
<PropertyGroup Condition=" $(IsNetFramework) ">
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
</PropertyGroup>
</Project>
7 changes: 4 additions & 3 deletions src/Dapper.Oracle/Dapper.Oracle.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,22 @@
<Import Project="..\common.targets" />
<PropertyGroup>
<IsTestProject>false</IsTestProject>
<TargetFrameworks>netstandard2.0;net452</TargetFrameworks>
<TargetFrameworks>netstandard2.0;net461</TargetFrameworks>
</PropertyGroup>

<ItemGroup Condition=" $(IsNetFramework) ">
<Reference Include="Microsoft.CSharp" />
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Data" />
<Reference Include="System.Runtime.Serialization" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Dapper" Version="1.50.2" />
<PackageReference Include="Dapper" Version="2.0.35" />
</ItemGroup>
<PropertyGroup Condition=" $(IsNetFramework) ">
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
</PropertyGroup>
</Project>
4 changes: 2 additions & 2 deletions src/Dapper.Oracle/OracleDynamicParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ public IEnumerable<string> ParameterNames
/// <returns>The value, note DBNull.Value is not returned, instead the value is returned as null</returns>
public T Get<T>(string name)
{
var paramInfo = Parameters[Clean(name)];
var paramInfo = GetParameter(name);
var attachedParam = paramInfo.AttachedParam;
object val = attachedParam == null ? paramInfo.Value : attachedParam.Value;
if (val == DBNull.Value)
Expand All @@ -174,7 +174,7 @@ public T Get<T>(string name)

public OracleParameterInfo GetParameter(string name)
{
return OracleMethodHelper.GetParameterInfo(Parameters[Clean(name)].AttachedParam);
return Parameters[Clean(name)];
}

void SqlMapper.IDynamicParameters.AddParameters(IDbCommand command, SqlMapper.Identity identity)
Expand Down
101 changes: 58 additions & 43 deletions src/Dapper.Oracle/OracleValueConverter.cs
Original file line number Diff line number Diff line change
@@ -1,73 +1,88 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data.Common;
using System.Linq;
using System.Reflection.Emit;
using System.Text.RegularExpressions;

namespace Dapper.Oracle
{
internal static class OracleValueConverter
{
private static string[] OracleStringTypes { get; } = { "Oracle.DataAccess.Types.OracleString", "Oracle.ManagedDataAccess.Types.OracleString" };

public static T Convert<T>(object val)
/// <summary>
/// Convert the value to the provided generic type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <returns></returns>
public static T Convert<T>(object value)
{
if (val == null)
value = GetValue(value);

if (value == null || value == DBNull.Value)
{
return default(T);
}

if (val == DBNull.Value)
// Convert the Oracle native data type to .NET data type.
// See: https://docs.oracle.com/en/database/oracle/oracle-database/19/clrnt/datatype-conversion.html#GUID-70A2F34D-AB7F-4E0C-89C9-452A45FF1CAC
if (value is IConvertible)
{
if (default(T) != null)
{
throw new ApplicationException("Attempting to cast a DBNull to a non nullable type!");
}

return default(T);
var nullableType = Nullable.GetUnderlyingType(typeof(T));
return (T)System.Convert.ChangeType(value, nullableType ?? typeof(T));
}

Type valueType = val.GetType();
if (typeof(T) == typeof(string) && OracleStringTypes.Contains(valueType.FullName))
{
// Need this, because... you know,Oracle...
val = val.ToString();
return default(T);
}

if ((string)val == "null") // Seriously. W.T.F ????
{
return default(T);
}
/// <summary>
/// Gets the underlying primitive value from a nested type instance.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
private static object GetValue(object value)
{
if (value == null || value == DBNull.Value)
{
return null;
}

return (T)val;
// Recursively handle nested database parameters.
// An OracleParameter can have a value that is an instance of an Oracle data structure (OracleBlob, OracleDecimal, etc.).
// This assumes we want the underlying primitive value of the parameter.
while (value is DbParameter parameter)
{
value = parameter.Value;
}

// We need this, because, you know, Oracle. OracleDecimal,OracleFloat,OracleYaddiAddy,OracleYourUncle etc value types.
if (Regex.IsMatch(valueType.FullName, @"Oracle\.\w+\.Types\.Oracle\w+"))
Type valueType = value.GetType();

if (IsOracleDataStructure(valueType))
{
// Fix Oracle 11g (to not throw the exception "Invalid operation on null data" if a function returns NULL)
var isNullProperty = valueType.GetProperty("IsNull");
if (isNullProperty != null && isNullProperty.CanRead)
{
var isNull = (bool)isNullProperty.GetValue(val);
if (isNull)
{
if (default(T) != null)
{
throw new ApplicationException("Attempting to cast a DBNull to a non nullable type!");
}
return default(T);
}
// If not isNull, continue and get the Value
}
var isNull = (bool)valueType.GetProperty("IsNull", typeof(bool))?.GetValue(value);

var valueProperty = valueType.GetProperty("Value");
if (valueProperty != null && valueProperty.CanRead)
if (isNull)
{
object reflected = valueProperty.GetValue(val);
return (T)reflected;
return null;
}

value = valueType.GetProperty("Value")?.GetValue(value);
}

return (T)System.Convert.ChangeType(val, typeof(T));
return value;
}

/// <summary>
/// Determine if the type is an Oracle data structure.
/// </summary>
/// <param name="valueType"></param>
/// <returns></returns>
private static bool IsOracleDataStructure(Type valueType)
{
// We need this, because, you know, Oracle. OracleDecimal,OracleFloat,OracleYaddiAddy,OracleYourUncle etc value types.
// See: https://docs.oracle.com/en/database/oracle/oracle-database/19/odpnt/intro003.html#GUID-425C9EBA-CFFC-47FE-B490-604251714ACA
return Regex.IsMatch(valueType.FullName, @"Oracle\.\w+\.Types\.Oracle\w+");
}
}
}
13 changes: 13 additions & 0 deletions src/Tests.Dapper.Oracle/OracleDynamicParameterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -160,5 +160,18 @@ public void GetParameterValue()

testObject.Get<string>("Foo").Should().Be("Bar");
}

[Fact]
public void GetParameter()
{
testObject.Add("Foo", "Bar", OracleMappingType.Varchar2);

var param = testObject.GetParameter("Foo");

param.Should().NotBeNull();
param.Name.Should().Be("Foo");
param.Value.Should().Be("Bar");
param.DbType.Should().Be(OracleMappingType.Varchar2);
}
}
}
Loading

0 comments on commit a92447a

Please sign in to comment.