You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Microsoft.SqlServer.Types(106.1000.6)获取自定义类型值时抛出异常求助

迁移至Microsoft.Data.SqlClient时SqlGeography类型GetValue抛出空参数异常问题

我们正从System.Data.SqlClient迁移至Microsoft.Data.SqlClient,在处理自定义类型的SqlGeography对象操作时遇到问题:可成功创建SqlDataRecord并获取序号值,但调用GetValue方法时抛出异常:
Value cannot be null. (Parameter 'key')

异常堆栈跟踪

at System.ThrowHelper.ThrowArgumentNullException(String name)
at System.Collections.Concurrent.ConcurrentDictionary`2.TryGetValue(TKey key, TValue& value)
at Microsoft.Data.SqlClient.Server.SerializationHelperSql9.GetSerializer(Type t)
at Microsoft.Data.SqlClient.Server.SerializationHelperSql9.Deserialize(Stream s, Type resultType)
at Microsoft.Data.SqlClient.Server.ValueUtilsSmi.GetUdt_LengthChecked(SmiEventSink_Default sink, ITypedGettersV3 getters, Int32 ordinal, SmiMetaData metaData)
at Microsoft.Data.SqlClient.Server.ValueUtilsSmi.GetValue(SmiEventSink_Default sink, ITypedGettersV3 getters, Int32 ordinal, SmiMetaData metaData, Object context)
at Microsoft.Data.SqlClient.Server.ValueUtilsSmi.GetValue200(SmiEventSink_Default sink, SmiTypedGetterSetter getters, Int32 ordinal, SmiMetaData metaData, Object context)
at Microsoft.Data.SqlClient.Server.SqlDataRecord.GetValueFrameworkSpecific(Int32 ordinal)
at Microsoft.Data.SqlClient.Server.SqlDataRecord.GetValue(Int32 ordinal)
at SqlGeographyTest.Program.Main(String[] args) in C:\source\repos\SqlServerTestError\SqlServerTestError\Program.cs:line 27

可复现代码示例

using Microsoft.Data.SqlClient.Server;
using Microsoft.SqlServer.Types;
using System.Data;

namespace SqlGeographyTest
{
    class Program
    {
        static void Main(string[] args)
        {
            SqlGeography geog = CreateGeographyPoint(40, 90);
            var md1 = new SqlMetaData("ID", SqlDbType.Int);
            var md2 = new SqlMetaData("geog", SqlDbType.Udt, typeof(SqlGeography), "geography");

            SqlMetaData[] metadata = [md1, md2];

            SqlDataRecord record = new SqlDataRecord(metadata);

            record.SetValues(1, geog);
            var checkValue = record.GetValue(0);
            var checkValue2 = record.GetOrdinal("geog");
            try
            {
                var checkValue3 = record.GetValue(1);
            }
            catch(Exception ex)
            {
                string errorMessage = ex.Message;
            }
        }

        public static SqlGeography CreateGeographyPoint(double longitude, double latitude)
        {
            var text = string.Format("POINT({0} {1})", longitude, latitude);
            var ch = new System.Data.SqlTypes.SqlChars(text);
            return Microsoft.SqlServer.Types.SqlGeography.STPointFromText(ch, 4326);
        }
    }
}

排查思路

  • 调整SqlMetaData构造参数:创建UDT类型的SqlMetaData时,移除第四个参数"geography",改用new SqlMetaData("geog", SqlDbType.Udt, typeof(SqlGeography))。该参数是SQL Server端的类型名称,Microsoft.Data.SqlClient的客户端序列化逻辑可能不需要此参数,多余参数会导致类型匹配失败。
  • 验证依赖版本兼容性:确保引用的Microsoft.SqlServer.Types版本在v14.0.3049.1及以上,该版本开始适配Microsoft.Data.SqlClient的序列化逻辑,旧版本会出现字典查找空键的问题。
  • 使用强类型取值方法:替换GetValue(int ordinal)为GetValue<SqlGeography>(int ordinal),强类型方法直接针对目标类型处理,绕过通用序列化字典的查找流程。
  • 手动注册UDT序列化器:在程序初始化时添加以下代码,手动将SqlGeography类型注册到序列化字典中:
    using Microsoft.Data.SqlClient.Server;
    // ...
    SerializationHelperSql9.RegisterSerializer(typeof(SqlGeography), (stream, obj) => ((SqlGeography)obj).Write(stream), (stream) => SqlGeography.Read(stream));
    
  • 检查SqlGeography对象有效性:调用geog.STAsText().ToString()验证对象是否正常初始化,排除对象本身为空或损坏的情况。

内容的提问来源于stack exchange,提问作者JJMar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 12:15:21