我正在执行SQL命令以在数据库表中创建新记录并获取所创建记录的ID。但是,SQL命令(未初始化的非空字段)生成的约束错误未被VB代码拾取。代码大致是: -
connection = New SqlConnection(connection_string)
connection.Open()
sql_command = New SqlCommand(command) 'command = the SQL command to execute
sql_command.Connection = connection
sql_command.Parameters.AddRange(sql_parameters.ToArray()) ' sql_parameters is a parameter to the function
reader = sql_command.ExecuteReader()
If reader IsNot Nothing Then
If reader.HasRows Then
While reader.Read
response_handler(reader, data) 'response handler is a callback which populates the data object
End While
End If
reader.Close()
End If
reader对象非空,但不包含任何数据,也不会生成异常。 SQL命令是: -
insert into [table] ([column1], [column2], [column3], [column4])
output Inserted.[pk]
values (@1, @2, @3, @4)
使用SQL Server Management Studio执行SQL语句,我收到错误: -
Msg 515,Level 16,State 2,Line 2
无法将值NULL插入列'somecolumn',表'tablename';列不允许空值。 INSERT失败。
我还在InfoMessage
对象上添加了SqlConnection
事件的处理程序,但即使我将FireInfoMessageEventOnUserErrors
设置为true,也不会调用该事件。
为什么我没有收到错误?确保向VB报告错误的正确方法是什么?
我正在使用Visual Studio 2008。
答案 0 :(得分:0)
严重性级别为16,不会中断当前会话。如果你想抛出一个硬错误,你可以在插入后直接添加这样的东西......
If @@Error <> 0
Begin
Raiserror('Constraint Error Encountered',20,1) With Log;
End
安全上下文必须具有sysadmin权限才能执行RAISERROR WITH LOG
,但如果你不能这样做,我确信还有其他方法可以抛出硬错误。无论如何,警告不会给VB代码带来错误。
答案 1 :(得分:0)
我不知道它内部是如何工作的,但属性HasRows
是由SqlDataReader类中的私有方法设置的,类似于TryGetNextResult
,它使用了很多try / catch块设置布尔输出参数,因此此方法不会抛出任何异常,甚至提供有关任何错误的任何反馈。我无法解决的问题是它是如何实现的,即使没有尝试插入也会出现错误,但确实如此。
使用此示例表:
CREATE TABLE T (ID INT IDENTITY, A INT NOT NULL);
我跑了:
string sql = @"INSERT T (A) OUTPUT inserted.ID, inserted.A VALUES (1);";
using (var connection = new SqlConnection(connectionString))
using (var command = new SqlCommand(sql, connection))
{
connection.Open();
using (var reader = command.ExecuteReader())
{
Console.WriteLine(reader.HasRows); // True
while (reader.Read())
{
Console.WriteLine(reader.GetInt32(1)); // 1
}
}
}
当我改变这个以尝试插入null时,reader.HasRows
是假的,但是通过在我调用reader.Read()之前我可以测试一个断点,这表明了它的标识值表T没有变化,因此读者无法通过简单回滚事务来验证插入。对我来说,为什么SqlDataReader能够识别出这个插入在执行之前会失败,这是一个谜,但是如果SQL被执行,它仍然会在引发错误之前尝试插入。
为了进一步证明行为,我使用简单的select命令运行了类似的测试,并看到了相同的行为:
static void Main(string[] args)
{
string sql = @" SELECT Date = CAST(D AS DATE)
FROM (VALUES
(1, '20130129'),
(2, '20130130'),
(3, '20130131'),
(4, '20130132')
) t (A, D)
ORDER BY A;";
using (var connection = new SqlConnection(connectionString))
using (var command = new SqlCommand(sql, connection))
{
connection.Open();
using (var reader = command.ExecuteReader())
{
Console.WriteLine(reader.HasRows); // false
while (reader.Read()) // Exception
{
Console.WriteLine(reader.GetString(0));
}
}
}
}
再次显示,SqlDataReader在某种程度上已经发现将20130132
转换为日期时会出错。如果我从SQL中删除此行,HasRows
属性将变为true。
我意识到这实际上并没有回答你的问题但是评论太长了,希望它会有所帮助,并且/或者可能会提示一些比c更了解c#的人来添加他们自己的答案。
答案 2 :(得分:0)
如果出现错误,HasRows
调用将返回false。这样你就永远不会看到错误。删除两个If
语句。空检查是多余的,另一个是抑制错误。