C# 未调用Dapper TypeHandler.SetValue()

C# 未调用Dapper TypeHandler.SetValue(),c#,dapper,C#,Dapper,我正在测试Dapper,以便将对象加载/持久化到Oracle数据库,并且为了管理Oracle的Guid存储,我需要一个SqlMapper.TypeHandler。从数据库加载Guid列时,会调用Parse方法,但当我尝试使用Guid参数执行SQL语句时,会出现以下异常: System.ArgumentException未处理;消息=值不下降 在预期范围内。Source=Oracle.DataAccess 在debug中,我可以看到从数据库加载类时调用了处理程序的Parse()方法,但SetVal

我正在测试Dapper,以便将对象加载/持久化到Oracle数据库,并且为了管理Oracle的Guid存储,我需要一个
SqlMapper.TypeHandler
。从数据库加载Guid列时,会调用Parse方法,但当我尝试使用Guid参数执行SQL语句时,会出现以下异常:

System.ArgumentException未处理;消息=值不下降 在预期范围内。Source=Oracle.DataAccess

在debug中,我可以看到从数据库加载类时调用了处理程序的Parse()方法,但SetValue()方法没有调用

下面是重现异常的代码



使用系统;
使用System.Linq;
使用整洁;
使用Oracle.DataAccess.Client;
名称空间程序
{
公开课Foo
{
公共Guid Id{get;set;}
公共字符串名称{get;set;}
}
类GuidTypeHandler:SqlMapper.TypeHandler
{
公共重写Guid解析(对象值)
{
WriteLine(“处理{0}的解析”,值);
var inVal=(字节[])值;
字节[]outVal=新字节[]{inVal[3],inVal[2],inVal[1],inVal[0],inVal[5],inVal[4],inVal[7],inVal[6],inVal[8],inVal[9],inVal[10],inVal[11],inVal[12],inVal[13],inVal[14],inVal[15];
返回新的Guid(outVal);
}
公共覆盖无效设置值(System.Data.IDbDataParameter参数,Guid值)
{
WriteLine(“处理{0}的Setvalue”,value);
var inVal=value.ToByteArray();
字节[]outVal=新字节[]{inVal[3],inVal[2],inVal[1],inVal[0],inVal[5],inVal[4],inVal[7],inVal[6],inVal[8],inVal[9],inVal[10],inVal[11],inVal[12],inVal[13],inVal[14],inVal[15];
参数.Value=outVal;
}
}
班级计划
{
静态void Main(字符串[]参数)
{
AddTypeHandler(新的GuidTypeHandler());
var conn=新的OracleConnection(Resources.ConnectionString);
var def=newcommanddefinition(“从foo中选择id、名称”);
conn.Open();
var foo=conn.Query(def.First();
Console.WriteLine(foo.Id+“;”+foo.Name);
foo.Name=“新建酒吧”;
def=新命令定义(
“更新foo SET name=:name,其中id=:id”,
参数:new{ID=foo.ID,NAME=foo.NAME});
变量行=conn.Execute(def);
WriteLine(“{0}行插入”,行);
Console.ReadLine();
}
}
}

我通过围绕.NET Guid类编写包装来解决这个问题。这并不理想,因为最终在DTO类中使用了包装器,但它可以工作

包装器类:

public class OracleGuid
{
    private Guid dotNetGuid;

    public OracleGuid(Guid guid)
    {
        this.dotNetGuid = guid;
    }

    public OracleGuid(Byte[] byteArray)
    {
        this.dotNetGuid = new Guid(byteArray);

    }

    public Guid InternalGuid { get { return dotNetGuid; } }
}
public class FooDto
{
    public OracleGuid Id { get; set; }
    public string Name { get; set; }
}
处理程序类:

public class OracleGuidHandler : SqlMapper.TypeHandler<OracleGuid>
{
    public override OracleGuid Parse(object value)
    {
        return new OracleGuid((byte[]) value);
    }

    public override void SetValue(System.Data.IDbDataParameter parameter, OracleGuid value)
    {
        parameter.Value = value.InternalGuid.ToByteArray();
    }
}
注意,我使用RAW(16)将这些存储在Oracle中,而不是内置的Oracle GUI中

编辑
看起来这可能是一个bug,可能已经修复:。看起来它还没有进入NuGet软件包,所以我还没有尝试过。

如果其他人偶然发现这篇文章有类似的问题,我找到了一个解决方案,可以在不需要包装的情况下处理
Guid
s

Dapper中的问题是Dapper搜索匹配的
DbType
TypeHandler
实现的顺序。对于
Guid
(在
SqlMapper#LookupDbType
中),Dapper更喜欢使用“本机”
DbType
。为了使Dapper使用您自己的实现,除了添加您自己的
TypeHandler
,您还必须删除默认映射:

SqlMapper.AddTypeHandler<Guid>(new GuidTypeHandler());
SqlMapper.RemoveTypeMap(typeof(Guid));
SqlMapper.RemoveTypeMap(typeof(Guid?));

你有没有想过如何让它发挥作用?当我尝试将自定义对象数组传递到查询(例如,“SELECT*FROM myTable WHERE id=ANY(:ids)”和typeof(:ids)==typeof(myType[])时,我遇到了类似的问题。如果运气不好,可能值得在Github上的Dapper问题列表中重新发布查询。
public class FooDto
{
    public OracleGuid Id { get; set; }
    public string Name { get; set; }
}
SqlMapper.AddTypeHandler<Guid>(new GuidTypeHandler());
SqlMapper.RemoveTypeMap(typeof(Guid));
SqlMapper.RemoveTypeMap(typeof(Guid?));
public class GuidAsStringHandler : SqlMapper.TypeHandler<Guid>
{
    public override Guid Parse(object value)
    {
        return new Guid((string) value);
    }

    public override void SetValue(IDbDataParameter parameter, Guid value)
    {
        parameter.Value = value.ToString();
    }
}