SqlDataAdapter.FillSchema SQL 2017 年未获取 DataTable
SqlDataAdapter.FillSchema not getting DataTable on SQL 2017
我不知道为什么,但是当我在 MSSQL 2012 和 2015 上执行该代码时一切正常(我正在将数据Table 的架构接收到声明的数据集),而当我在 MSSQL 2017 上执行此操作时 - FillSchema 对数据集没有任何作用。
DataSet.Tables.Count 等于 0.
下面是示例代码:
var da = new SqlDataAdapter();
var cn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["Test"].ConnectionString);
try
{
cn.Open();
var sql = "SELECT * FROM MyTable T" +
"WHERE T.MyTableId=123 AND " +
"EXISTS" +
"(" +
" SELECT * FROM dbo.MyFunction() CTX WHERE ISNULL(T.MyOtherId, -1) = CTX.MyOtherId" +
")";
da.SelectCommand = new SqlCommand(sql, cn);
var ds = new DataSet();
da.FillSchema(ds, SchemaType.Source);
//There no table in the DataSet!
}
catch (Exception ex)
{
MessageBox.Show("Error " + ex.Message);
}
finally
{
cn.Close();
}
MS SQL 2017 有什么变化吗?或者我做错了什么?
编辑 1: 当我从查询中删除 EXISTS 条件时,问题就消失了。我认为调用函数可能是原因。
编辑 2: 当我将查询简化为:
var sql = "SELECT * FROM dbo.MyFunction()";
仍然无法正常工作...您可能想知道 SQL 中的 MyFunction 做了什么。这是一个多语句 Table 函数:
CREATE FUNCTION dbo.MyFunction ()
RETURNS @RESULT TABLE
(
ID BIGINT NOT NULL,
NAME VARCHAR(50),
CODE VARCHAR(50)
)
AS
BEGIN
INSERT INTO @RESULT VALUES(1, 'Name', 'NAME')
RETURN
END
GO
当我将 Multi-Statement Table 函数重写为 Inline-Statement 时,它起作用了。
我知道这不是 .NET 中接收模式的最佳方式...但是知道为什么多语句函数不起作用吗?
发生这种情况是因为 SQL 在 SET FMTONLY ON
, which is still the method used by ADO.NET to retrieve metadata. It's been deprecated, and sp_describe_first_result_set
does work correctly for this case, but that's still no reason for SQL Server 2017 to fail. This has been reported as a bug 下执行 SELECT * FROM dbo.MyFunction()
时,Server 2017 没有 return 元数据。
推测:这个错误可能是作为新 interleaved execution feature 的副作用引入的,它改变了这些函数的执行方式。如果数据库兼容级别下降到 130,它就会消失,这会禁用它(除其他外),这一点得到了加强。我不知道有一个跟踪标志只禁用交错执行,可以用来测试这个。
有一种变通方法:即使在兼容级别 140 下,set fmtonly on; exec ('select * from dbo.MyFunction()'); set fmtonly off
也会 return 元数据,因此使用 EXEC
获取查询的元数据仍然有效。在上面,
var sql = "EXEC ('SELECT * FROM dbo.MyFunction()')";
应该 return 结果。
我不知道为什么,但是当我在 MSSQL 2012 和 2015 上执行该代码时一切正常(我正在将数据Table 的架构接收到声明的数据集),而当我在 MSSQL 2017 上执行此操作时 - FillSchema 对数据集没有任何作用。
DataSet.Tables.Count 等于 0.
下面是示例代码:
var da = new SqlDataAdapter();
var cn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["Test"].ConnectionString);
try
{
cn.Open();
var sql = "SELECT * FROM MyTable T" +
"WHERE T.MyTableId=123 AND " +
"EXISTS" +
"(" +
" SELECT * FROM dbo.MyFunction() CTX WHERE ISNULL(T.MyOtherId, -1) = CTX.MyOtherId" +
")";
da.SelectCommand = new SqlCommand(sql, cn);
var ds = new DataSet();
da.FillSchema(ds, SchemaType.Source);
//There no table in the DataSet!
}
catch (Exception ex)
{
MessageBox.Show("Error " + ex.Message);
}
finally
{
cn.Close();
}
MS SQL 2017 有什么变化吗?或者我做错了什么?
编辑 1: 当我从查询中删除 EXISTS 条件时,问题就消失了。我认为调用函数可能是原因。
编辑 2: 当我将查询简化为:
var sql = "SELECT * FROM dbo.MyFunction()";
仍然无法正常工作...您可能想知道 SQL 中的 MyFunction 做了什么。这是一个多语句 Table 函数:
CREATE FUNCTION dbo.MyFunction ()
RETURNS @RESULT TABLE
(
ID BIGINT NOT NULL,
NAME VARCHAR(50),
CODE VARCHAR(50)
)
AS
BEGIN
INSERT INTO @RESULT VALUES(1, 'Name', 'NAME')
RETURN
END
GO
当我将 Multi-Statement Table 函数重写为 Inline-Statement 时,它起作用了。 我知道这不是 .NET 中接收模式的最佳方式...但是知道为什么多语句函数不起作用吗?
发生这种情况是因为 SQL 在 SET FMTONLY ON
, which is still the method used by ADO.NET to retrieve metadata. It's been deprecated, and sp_describe_first_result_set
does work correctly for this case, but that's still no reason for SQL Server 2017 to fail. This has been reported as a bug 下执行 SELECT * FROM dbo.MyFunction()
时,Server 2017 没有 return 元数据。
推测:这个错误可能是作为新 interleaved execution feature 的副作用引入的,它改变了这些函数的执行方式。如果数据库兼容级别下降到 130,它就会消失,这会禁用它(除其他外),这一点得到了加强。我不知道有一个跟踪标志只禁用交错执行,可以用来测试这个。
有一种变通方法:即使在兼容级别 140 下,set fmtonly on; exec ('select * from dbo.MyFunction()'); set fmtonly off
也会 return 元数据,因此使用 EXEC
获取查询的元数据仍然有效。在上面,
var sql = "EXEC ('SELECT * FROM dbo.MyFunction()')";
应该 return 结果。