Attempting to migrate away from System.Data.SqlClient, we ran into a snag around operations using SqlGeography objects when dealing with user defined types. In short, I am able to setup and retrieve the ordinal value in a simple SqlDataRecord construct, but retrieving the value returns the following exception:
Value cannot be null. (Parameter 'key')
Stack Trace:
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
Any insight of where I'm going awry would be fantastic. Thank you.
Code example that reproduces the issue:
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);
}
}
}
I would have expected the SqlGeography object to be returned instead of an exception thrown.
Not sure why it does not work, possibly it is worth reporting to Microsoft, but you can try workaround with manually deserializing SqlBytes
:
var sqlBytes = record.GetSqlBytes(1);
var deserialize = SqlGeography.Deserialize(sqlBytes);