簡體   English   中英

查詢從 C# 返回與 SSMS 不同的結果

[英]Query returns different result from C# then from SSMS

我有一個我無法解釋的奇怪問題

當我從 C# 應用程序運行某個查詢時,它返回的結果與我在 SSMS 中運行它時返回的結果不同,但當我使用參數時返回的結果不同

命令是這樣的

select dbo.fnGetPlaceID('6025', null, null)

從 c# 應用程序運行時返回 -1,從 SSMS 運行時返回 1489

但如果我這樣做

declare @DealerCode varchar(30) = '6025'
declare @RegionCode varchar(50) = null
declare @MerkID int = null
select dbo.fnGetPlaceID(@DealerCode, @RegionCode, @MerkID)

然后它也從 c# 應用程序返回正確的值 1489

那么區別是什么呢?

附加代碼:

CREATE function dbo.fnGetPlaceID(@DealerCode varchar(30), @RegionCode varchar(50), @MerkID int) returns int as
begin
    declare @Result int = -1
    
    if @RegionCode = ''
       set @RegionCode = null
    
    select @Result = r.RelationID
    from   relation.tblRelation r
    where  r.dealercode = @DealerCode
    
    -- in the example of '6025' there is only one row, I checked this
    -- So the code below should not be executed    
    if @@ROWCOUNT <> 1
    begin
         select @Result = rel.RelationID
         from   relation.tblRelation rel
           left outer join dbo.tblRegionCodes r on rel.RegionCodeID = r.FordRegionCodeID
         where  rel.dealercode = @DealerCode
         and    (@RegionCode is null or r.RegionCode = @RegionCode)
         and    (@MerkID is null or rel.BrandID = @MerkID)
         
         if @@ROWCOUNT <> 1
            set @Result = -1
    end
    
    return @Result
end

和 c# 中的代碼

FillDataTable(myDataTable, "select dbo.fnGetPlaceID('6025', null, null)")

public void FillDataTable(DataTable table, string SqlText, int commandTimeOut = 300)
{
    if (_ConnectionString != null && _ConnectionString != "")
    {
        using (SqlConnection connection = new SqlConnection(_ConnectionString))
        {
            OpenConnection(connection, SqlText);

            using (SqlCommand command = new SqlCommand(SqlText, connection))
            {
                command.CommandType = CommandType.Text;
                command.CommandTimeout = commandTimeOut;

                using (SqlDataAdapter adapter = new SqlDataAdapter(command))
                {
                    try
                    {
                        adapter.Fill(table);
                    }
                    catch (Exception ex)
                    {
                        throw new Exception(ex.Message);
                    }
                }
            }
        }
    }
}

我試過的

然后我在 sql function 中嘗試了這個改變

alter function dbo.fnGetPlaceID(@DealerCode varchar(30), @RegionCode varchar(50), @MerkID int) returns int as
begin
    declare @Result int = -1
    
    if @RegionCode = ''
       set @RegionCode = null
    
    select @Result = r.RelationID
    from   relation.tblRelation r
    where  r.dealercode = @DealerCode
/*    
    -- in the example of '6025' there is only one row, I checked this
    -- So the code below should not be executed
    if @@ROWCOUNT <> 1
    begin
         select @Result = rel.RelationID
         from   relation.tblRelation rel
           left outer join dbo.tblRegionCodes r on rel.RegionCodeID = r.FordRegionCodeID
         where  rel.dealercode = @DealerCode
         and    (@RegionCode is null or r.RegionCode = @RegionCode)
         and    (@MerkID is null or rel.BrandID = @MerkID)
         
         if @@ROWCOUNT <> 1
            set @Result = -1
    end
*/    
    return @Result
end

現在它在 c# 應用程序中確實可以正常工作。

因此,出於某種原因,當我從 c# 應用程序調用此 function 時,@@ROWCOUNT 似乎不等於 1,而當我從 SSMS 調用此 function 時,@@ROWCOUNT 等於 1。
我還沒有證實這一點,但這是我的結論。
問題仍然存在,為什么?
還有為什么當我使用參數時它的工作方式不同?

我已通過將 function 更改為來解決我的問題

select @Count = count(1) 
from   relation.tblRelation r 
where  r.DealerCode = @DealerCode

然后使用變量@Count 代替rowcount,但我仍然想對這里發生的事情做一些解釋。

我還檢查了如果找到多行,第一個查詢會發生什么。
因為我將查詢結果放在一個變量中,所以如果找到不止一行,那應該會失敗(我的 function 中的一個錯誤,我知道,我現在已經修復了)

declare @Result int = -1

select @Result = r.RelationID
from   relation.tblRelation r
where  r.dealercode is null

select @@ROWCOUNT

但是 rowcount 並沒有像我預期的那樣拋出異常,而是只有 4512 的值

編輯

正如@DanGuzman 所建議的,當我將 TSQL_SCALAR_UDF_INLINING 設置為 OFF 時它會起作用

select dbo.fnGetPlaceID('6025', null, null)
OPTION (USE HINT('DISABLE_TSQL_SCALAR_UDF_INLINING'))

編輯 2

如果我這樣做,它也可以在沒有提示的情況下工作ALTER DATABASE [myDataBase] SET COMPATIBILITY_LEVEL = 140; 它是在 150

最后更新

我今天安裝了 CU15,並在兼容級別設置為 150 的情況下再次進行了測試,現在它也可以從 c# 開始正常工作。所以這個解決方案現在得到了確認。

自初始 SQL Server 2019 RTM 版本以來,標量 function 內聯存在許多問題。 安裝最新的累積更新以獲取這些修復程序和其他修復程序。

如果不打補丁,解決方法包括:

  • 使用查詢提示OPTION (USE HINT('DISABLE_TSQL_SCALAR_UDF_INLINING'))
  • USE YourDatabase;ALTER DATABASE SCOPED CONFIGURATION SET TSQL_SCALAR_UDF_INLINING = OFF;
  • 將數據庫兼容級別更改為 140 或更低

本頁列出最新SQL服務器補丁下載鏈接

關於 C# 代碼和 SSMS 的不同行為,這是由於不同的執行計划。 SSMS 查詢默認指定ARITHABORT ON session 設置,而 C# 不設置該選項。 不同的 session 設置可能會產生不同的執行計划並使故障排除變得困難 有關詳細信息,請參閱Erland Sommarskog 的文章。 我要補充一點,SSMS 設置 ARITHABORT 只是為了向后兼容。 在 SQL 2019 世界中,它默認處於打開狀態,因為不再支持數據庫兼容級別 80 (SQL 2000)。 考慮在工具-->選項-->查詢執行-->SQL Server--高級下取消選中 SSMS 中的SET ARITHABORT選項。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM