Dapper怎么处理自定义SQL类型 Dapper UDT映射方法

发布时间 - 2026-01-03 00:00:00    点击率:
Dapper通过自定义ITypeHandler实现SQL Server UDT双向映射:SetValue序列化.NET实例为byte[]并设UdtTypeName,Parse反序列化byte[]为UDT实例;需注册处理器、确保UDT类符合序列化规范,并注意类型匹配与空值处理。

Dapper 本身不直接支持 SQL Server 的用户定义类型(UDT),但可以通过自定义 ITypeHandler 实现 UDT 的双向映射——即 .NET 类型 ↔ 数据库 UDT 值。

注册UDT类型处理器

SQL Server 的 UDT(如 PointGeometry 或自定义 CLR 类型)需在数据库中已注册,并在 .NET 端有对应类(通常实现 INullableIBinarySerialize)。Dapper 依靠 ITypeHandler 完成转换:

  • SetValue:把 .NET UDT 实例序列化为 SqlBytesbyte[],并设置 parameter.UdtTypeName
  • Parse:从数据库返回的 SqlBytesobject 反序列化为 UDT 实例

示例(以自定义 UDT MyUdt 为例):

public class MyUdtHandler : SqlMapper.ITypeHandler
{
    public void SetValue(IDbDataParameter parameter, object value)
    {
        parameter.Value = value == null ? DBNull.Value : ((MyUdt)value).ToBinary();
        parameter.UdtTypeName = "dbo.MyUdt"; // 必须与数据库中注册名一致
    }

    public object Parse(Type destinationType, object value)
    {
        if (value == null || value == DBNull.Value) return null;
        var bytes = (byte[])value;
        return MyUdt.FromBinary(bytes);
    }
}

注册方式:

SqlMapper.AddTypeHandler(typeof(MyUdt), new MyUdtHandler());

确保UDT类符合SQL Server要求

.NET 端 UDT 类必须满足 SQL Server 的序列化规范,典型结构包括:

  • 标记 [Serializable][SqlUserDefinedType(Format.Native)](或 Format.UserDefined + IBinarySerialize 实现)
  • 提供静态 Parse() 和实例 ToBinary() 方法
  • 无参构造函数(用于反序列化)

若使用 Format.UserDefined,必须完整实现 IBinarySerialize.Read()Write()

配合Dapper.Contrib或QueryMultiple使用注意事项

UDT 字段在查询中默认无法自动映射到实体属性,除非:

  • 该属性类型与注册的 ITypeHandler 类型完全匹配(含可空性,如 MyUdt? 需额外注册)
  • 避免在 Query() 中混用未映射字段;建议显式 SELECT 所需列,或用匿名类型过渡
  • 插入/更新时,确保参数对象中 UDT 属性值非 null 或已正确处理 null 场景(如设为 DBNull.Value

替代方案:用内置类型绕过UDT(适用简单场景)

如果 UDT 仅用于封装简单数据(如坐标字符串、编码后的结构),更轻量的做法是:

  • 数据库层仍用 UDT 列,但 Dapper 层统一按 stringbyte[] 处理
  • 注册 stringMyUdt 的转换器(在业务逻辑中解析),而非让 Dapper 直接持有 UDT 类型
  • 这样可规避 UDT 部署依赖,也便于跨数据库兼容

基本上就这些。关键不是“能不能”,而是“谁负责序列化”——Dapper 把控制权交给你,你只需守住 SetValueParse 这两个入口。


# 处理器  # 编码  # app  # .net  # sql  # String  # Object  # NULL  # 封装  # 构造函数  # select  # format  # 字符串  # 对象  # 数据库  # 自定义  # 序列化  # 数据库中  # 只需  # 设为  # 并在  # 所需  # 这两个  # 可以通过  # 为例 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 网站图片在线制作软件,怎么在图片上做链接?  JavaScript常见的五种数组去重的方式  Win10如何卸载预装Edge扩展_Win10卸载Edge扩展教程【方法】  如何在企业微信快速生成手机电脑官网?  Laravel表单请求验证类怎么用_Laravel Form Request分离验证逻辑教程  如何快速搭建自助建站会员专属系统?  香港网站服务器数量如何影响SEO优化效果?  Laravel项目结构怎么组织_大型Laravel应用的最佳目录结构实践  网站广告牌制作方法,街上的广告牌,横幅,用PS还是其他软件做的?  教你用AI将一段旋律扩展成一首完整的曲子  Laravel事件监听器怎么写_Laravel Event和Listener使用教程  jimdo怎样用html5做选项卡_jimdo选项卡html5实现与切换效果【指南】  EditPlus 正则表达式 实战(3)  laravel怎么为应用开启和关闭维护模式_laravel应用维护模式开启与关闭方法  Angular 表单中正确绑定输入值以确保提交与验证正常工作  晋江文学城电脑版官网 晋江文学城网页版直接进入  如何用PHP快速搭建CMS系统?  Laravel如何安装使用Debugbar工具栏_Laravel性能调试与SQL监控插件【步骤】  使用PHP下载CSS文件中的所有图片【几行代码即可实现】  DeepSeek是免费使用的吗 DeepSeek收费模式与Pro版本功能详解  Laravel如何创建自定义Artisan命令?(代码示例)  如何构建满足综合性能需求的优质建站方案?  如何在阿里云完成域名注册与建站?  如何快速生成凡客建站的专业级图册?  Laravel如何使用Spatie Media Library_Laravel图片上传管理与缩略图生成【步骤】  HTML 中如何正确使用模板变量为元素的 name 属性赋值  利用 Google AI 进行 YouTube 视频 SEO 描述优化  Laravel如何处理CORS跨域问题_Laravel项目CORS配置与解决方案  Laravel如何处理文件上传_Laravel Storage门面实现文件存储与管理  如何快速生成高效建站系统源代码?  香港服务器部署网站为何提示未备案?  如何安全更换建站之星模板并保留数据?  大连网站制作费用,大连新青年网站,五年四班里的视频怎样下载啊?  如何为不同团队 ID 动态生成多个非值班状态按钮  哪家制作企业网站好,开办像阿里巴巴那样的网络公司和网站要怎么做?  如何在IIS中新建站点并配置端口与IP地址?  如何挑选最适合建站的高性能VPS主机?  手机网站制作平台,手机靓号代理商怎么制作属于自己的手机靓号网站?  Internet Explorer官网直接进入 IE浏览器在线体验版网址  如何自定义建站之星模板颜色并下载新样式?  google浏览器怎么清理缓存_谷歌浏览器清除缓存加速详细步骤  Laravel Asset编译怎么配置_Laravel Vite前端构建工具使用  Laravel策略(Policy)如何控制权限_Laravel Gates与Policies实现用户授权  HTML5空格和nbsp有啥关系_nbsp的作用及使用场景【说明】  奇安信“盘古石”团队突破 iOS 26.1 提权  为什么要用作用域操作符_php中访问类常量与静态属性的优势【解答】  如何在VPS电脑上快速搭建网站?  想要更高端的建设网站,这些原则一定要坚持!  如何选择可靠的免备案建站服务器?  公司网站制作价格怎么算,公司办个官网需要多少钱?