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
相关产品推荐
相关产品推荐

