I encounter that SqlCommand.ExecuteScalar()
returns NULL
sometimes in production environment.
I've crossed a lot of similar questions here, the most close one is: SqlCommand.ExecuteScalar returns null but raw SQL does not. But the advice given is not about my case.
The code sample is here:
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandText = "SELECT NEXT VALUE FOR Seq_Revision";
command.CommandType = CommandType.Text;
return (long)command.ExecuteScalar(); //<---ExecuteScalar() here returns NULL sometimes
}
}
Seq_Revision
here is simple MSSQL sequence like this:
CREATE SEQUENCE [dbo].[Seq_Revision]
AS [bigint]
START WITH 0
INCREMENT BY 1
MINVALUE -9223372036854775808
MAXVALUE 9223372036854775807
CACHE 10
GO
And I'm pretty sure that it will never actually return NULL.
Also I observe similar strange (non-repeatable behaviour) when NULL
is returned in this code sample, while I'm sure there is an entity with this ID:
NHibernate.ISession.Get<FooEntity>(entityId)
What is interesting, returning NULL
by this method correlates well with the time frames when there is a high disk activity on SQL node (disk queue length > ~50).
It may be important: we use AlwaysON cluster with 2 nodes, one of the nodes is used in read mode (ApplicationIntent=READONLY
in the connection string).
MSSQL version is:
Microsoft SQL Server 2014 (SP2-CU5) (KB4013098) - 12.0.5546.0 (X64)
Apr 3 2017 14:55:37
Copyright (c) Microsoft Corporation
Enterprise Edition: Core-based Licensing (64-bit) on Windows NT 6.3 <X64> (Build 9600: )
ExecuteScalar
returningnull
means: no rows were returned. If a row was returned with a null value, it would beDBNull.Value
. That doesn't answer "why?", but it may be useful context – TrygveNEXT VALUE FOR
does not support read only database. See Limitations and Restrictions at learn.microsoft.com/en-us/sql/t-sql/functions/… => remove ApplicationIntent=READONLY from connection string – Nanciif (command.GetType() == typeof(DBNull))
or it catch it with anInvalidCastException
and then check for the value or retry after aThread.Sleep(1000);
just to rule out a timing thing with the disk. Also a good place to add some logging to help form a minimal reproducible example, my guess is its intermittent and only reproducible under IO stress. – Garment