Dapper 2.1.86 读取 SERVERPROPERTY 到 bool 报 InvalidCastException
SERVERPROPERTY 返回 sql_variant,Dapper 2.1.86 映射布尔属性可能失败。显式返回 bit,保留 NULL 的未知含义,不改全局类型映射。
同样映射到 bool IsLocalDB,SELECT CAST(0 AS int) 能成功,换成 SERVERPROPERTY('IsLocalDB') 就出现 Error parsing column 0 (IsLocalDB=0 - Int32),内部还有 InvalidCastException。在 Dapper 2.1.86 与 Microsoft.Data.SqlClient 的组合中,应先看 SQL 返回列的类型,不能只看错误里显示的数值 0。
SQL Server 的 SERVERPROPERTY() 返回 sql_variant,IsLocalDB 这个属性的基础值是整数。值看起来相同,不代表 ADO.NET 交给映射器的列类型与普通 int 列相同。这条故障针对原始 sql_variant 到布尔属性的映射,不说明 Dapper 的所有整数转布尔值都失败。
在查询边界明确返回 bit
若调用方本来需要布尔含义,可以在这一列显式转换,保留模型使用的别名:
SELECT CAST(SERVERPROPERTY('IsLocalDB') AS bit) AS IsLocalDB;
这条查询只读取实例属性,不修改数据库配置。bit 接受 0、1 和 NULL;非零数值转换为 1。因此它适合这里已经明确的布尔属性,不能用于任意 sql_variant 内容,也不适合拿来压缩需要保留原数值的状态码。
在已有 SqlClient 连接上,可按下面的 DTO 结构接收:
using Dapper;
public sealed class ServerFlags
{
public bool? IsLocalDB { get; set; }
}
static ServerFlags ReadFlags(System.Data.IDbConnection connection)
{
const string sql =
"SELECT CAST(SERVERPROPERTY('IsLocalDB') AS bit) AS IsLocalDB";
return connection.QuerySingle<ServerFlags>(sql);
}
connection 由应用原来的连接管理入口提供,示例不另建或关闭它。使用 bool? 是为了保留 SQL NULL:属性名无效、不适用或查询出错时,SERVERPROPERTY() 可能返回 NULL,调用方要明确处理“未知”,不能悄悄当成 false。
若项目已经确认目标实例一定返回非空值,可以保留自己的非空契约,但应在查询或应用边界检查它。不要为避免异常就给所有服务器属性加上 COALESCE(..., 0),那会把不支持与明确否定混成一个结果。
留住列类型与版本的区别
原始故障已在 Dapper 2.1.86、SQL Server 2022 和 Microsoft.Data.SqlClient 组合中出现;同一查询在 Dapper 2.1.79 的对照可工作。这个版本对照用于定位变化,不是要求整个项目默认回退旧包。窄范围的 SQL 转换可以先把返回契约写清楚,避免为了一个服务器属性更改全局布尔映射。
普通表中真实的 bit 列仍报错,或者内部异常并非 Specified cast is not valid 时,应继续检查列别名、DTO 类型、驱动和自定义 type handler。Npgsql 的日期类型变化、数组转换错误也是不同路径,不能套用这条 SQL Server 查询。
修改前保留原 SQL 和实际依赖版本。验证时对照原始列与转换后列,确认目标实例上的真、假和未知结果都按模型处理,业务读取没有丢列或错别名。只看到异常消失,还不足以判断 NULL 的含义已经保留。


