Iga*_*and 6 join sql-server sql-server-2014
使用 SQL Server 2014。
给定带有rowversion列的表,要加入的其他表和这样的选择:
CREATE TABLE dbo.FooTable(
[Id] [int] IDENTITY(1,1) NOT NULL,
[RowVersion] [rowversion] NULL,
CONSTRAINT [PK_FooTable] PRIMARY KEY CLUSTERED
(
[Id] ASC
))
CREATE TABLE dbo.BarTable(
[Id] [int] IDENTITY(1,1) NOT NULL
CONSTRAINT [PK_BarTable] PRIMARY KEY CLUSTERED
(
[Id] ASC
))
Insert into BarTable default values
GO
SELECT *
FROM FooTable ft
FULL OUTER JOIN BarTable bt on ft.Id = Bt.Id
Run Code Online (Sandbox Code Playgroud)
选择的结果是:
Id RowVersion Id
NULL 0x 1
Run Code Online (Sandbox Code Playgroud)
如果与 BarTable 不匹配,则RowVersion 列不是 null,而是 0x。
这让我们用来在应用服务器上反序列化结果的 Dapper 感到困惑,认为它应该为行的 FooTable 部分构造一个对象——一个无效的对象,只包含一个空字节数组。
这种相当意外的行为有什么原因吗?
有没有比在 sql 语句中使用 CASE 将值转换回 null 或在应用程序代码中处理它更聪明的解决方案?
这似乎是 .NET 的 SqlClient 中的一个错误。byte[]
尽管该列null
在结果中被标记为空,但它仍被返回为空。
例如
using System;
using System.Data.Odbc;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Threading;
using System.Threading.Tasks;
using System.Transactions;
namespace ConsoleApp14
{
class Program
{
static void Main(string[] args)
{
using (var con = new SqlConnection("Server=localhost;database=tempdb;Integrated Security=true"))
{
con.Open();
var cmd = con.CreateCommand();
cmd.CommandText = "select cast(null as rowversion) rv";
using (var rdr = cmd.ExecuteReader())
{
rdr.Read();
var allowDbNull = rdr.GetColumnSchema()[0].AllowDBNull;
var isNull = rdr.IsDBNull(0);
var val = rdr[0];
Console.WriteLine($"SqlClient: AllowDbNull {allowDbNull} IsDbNull: {isNull} {val.GetType().Name} {val}");
}
}
using (var con = new SqlConnection("Server=localhost;database=tempdb;Integrated Security=true"))
{
con.Open();
var cmd = con.CreateCommand();
cmd.CommandText = "select @val = cast(null as rowversion) ";
var p = cmd.Parameters.Add(new SqlParameter("@val", System.Data.SqlDbType.Timestamp));
p.Direction = System.Data.ParameterDirection.Output;
cmd.ExecuteNonQuery();
{
SqlBinary val = (SqlBinary) p.SqlValue;
Console.WriteLine($"SqlClient (parameter): IsDbNull: {val.IsNull} {val.GetType().Name} {val}");
}
}
using (var con = new OdbcConnection("Driver={ODBC Driver 17 for SQL Server};Server=localhost;Trusted_Connection=yes"))
{
con.Open();
var cmd = con.CreateCommand();
cmd.CommandText = "select cast(null as rowversion) rv";
using (var rdr = cmd.ExecuteReader())
{
rdr.Read();
var allowDbNull = rdr.GetSchemaTable().Rows[0]["AllowDBNull"];
var isNull = rdr.IsDBNull(0);
var val = rdr[0];
Console.WriteLine($"ODBC: AllowDbNull {allowDbNull} IsDbNull: {isNull} {val.GetType().Name} {val}");
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
输出
SqlClient: AllowDbNull True IsDbNull: False Byte[] System.Byte[]
SqlClient (parameter): IsDbNull: True SqlBinary Null
ODBC: AllowDbNull True IsDbNull: True DBNull
Run Code Online (Sandbox Code Playgroud)
我在https://github.com/dotnet/SqlClient/issues/255上打开了一个问题 ,但它很可能会作为 WontFix 关闭。根据源中的注释
// Dev10 Bug #479607 - this should have been the same as SqlDbType.Binary, but it's a rejected breaking change
Run Code Online (Sandbox Code Playgroud)
该问题已被提出,但并未作为重大更改得到解决。它可能会在 .NET Core 中得到修复,无论如何,它都充满了重大更改,并在 .NET Framework 中保持原样。
归档时间: |
|
查看次数: |
268 次 |
最近记录: |