Ado.net Fill 方法在运行不存在的存储过程时不会抛出错误
我使用的是 Enterprise 库和 ADO 原始 Fill 方法的组合。这是因为我需要在捕获事件信息消息时自己打开和关闭命令连接,
这是到目前为止我的代码
// Set Up Command
SqlDatabase db = new SqlDatabase(ConfigurationManager.ConnectionStrings[ConnectionName].ConnectionString);
SqlCommand command = db.GetStoredProcCommand(StoredProcName) as SqlCommand;
command.Connection = db.CreateConnection() as SqlConnection;
// Set Up Events for Logging
command.StatementCompleted += new StatementCompletedEventHandler(command_StatementCompleted);
command.Connection.FireInfoMessageEventOnUserErrors = true;
command.Connection.InfoMessage += new SqlInfoMessageEventHandler(Connection_InfoMessage);
// Add Parameters
foreach (Parameter parameter in Parameters)
{
db.AddInParameter(command,
parameter.Name,
(System.Data.DbType)Enum.Parse(typeof(System.Data.DbType), parameter.Type),
parameter.Value);
}
// Use the Old Style fill to keep the connection Open througout the population
// and manage the Statement Complete and InfoMessage events
SqlDataAdapter da = new SqlDataAdapter(command);
DataSet ds = new DataSet();
// Open Connection
command.Connection.Open();
// Populate
da.Fill(ds);
// Dispose of the adapter
if (da != null)
{
da.Dispose();
}
// If you do not explicitly close the connection here, it will leak!
if (command.Connection.State == ConnectionState.Open)
{
command.Connection.Close();
}
...
现在,如果我传递到变量 StoredProcName = "ThisProcDoesNotExists"
并运行这段代码。 CreateCommand 也不是 da.Fill 通过错误消息。这是为什么呢。我可以判断它没有运行的唯一方法是它返回一个包含 0 个表的数据集。但在调查错误时,该程序并不存在。
编辑 经进一步调查 command.Connection.FireInfoMessageEventOnUserErrors = true; 导致错误被抑制到
来自 BOL 的
InfoMessage 事件中当您将 FireInfoMessageEventOnUserErrors 设置为 true 时,以前被视为异常的错误现在将作为 InfoMessage 事件进行处理。所有事件都会立即触发并由事件处理程序处理。如果 FireInfoMessageEventOnUserErrors 设置为 false,则在过程结束时处理 InfoMessage 事件。
我想要的是 Sql 中的每个打印语句都创建一个新的日志记录。将此属性设置为 false 将其合并为一个大字符串。因此,如果我将属性设置为 true,现在的问题是我能否从错误
另一个编辑
中辨别打印消息所以现在我有了代码,以便将标志设置为 true 并检查方法中的错误号
void Connection_InfoMessage(object sender, SqlInfoMessageEventArgs e)
{
// These are not really errors unless the Number >0
// if Number = 0 that is a print message
foreach (SqlError sql in e.Errors)
{
if (sql.Number == 0)
{
Logger.WriteInfo("Sql Message",sql.Message);
}
else
{
// Whatever this was it was an error
throw new DataException(String.Format("Message={0},Line={1},Number={2},State{3}", sql.Message, sql.LineNumber, sql.Number, sql.State));
}
}
}
现在的问题当我抛出错误时,它不会冒泡到进行调用的语句,甚至不会冒泡到上面的错误处理程序。它只是在那条线上爆炸了
填充看起来像
// Populate
try
{
da.Fill(ds);
}
catch (Exception e)
{
throw new Exception(e.Message, e);
}
现在即使我看到调用代码和方法仍然在调用堆栈中,这个异常似乎并没有冒泡?
I am using a combination of the Enterprise library and the original Fill method of ADO. This is because I need to open and close the command connection myself as I am capture the event Info Message
Here is my code so far
// Set Up Command
SqlDatabase db = new SqlDatabase(ConfigurationManager.ConnectionStrings[ConnectionName].ConnectionString);
SqlCommand command = db.GetStoredProcCommand(StoredProcName) as SqlCommand;
command.Connection = db.CreateConnection() as SqlConnection;
// Set Up Events for Logging
command.StatementCompleted += new StatementCompletedEventHandler(command_StatementCompleted);
command.Connection.FireInfoMessageEventOnUserErrors = true;
command.Connection.InfoMessage += new SqlInfoMessageEventHandler(Connection_InfoMessage);
// Add Parameters
foreach (Parameter parameter in Parameters)
{
db.AddInParameter(command,
parameter.Name,
(System.Data.DbType)Enum.Parse(typeof(System.Data.DbType), parameter.Type),
parameter.Value);
}
// Use the Old Style fill to keep the connection Open througout the population
// and manage the Statement Complete and InfoMessage events
SqlDataAdapter da = new SqlDataAdapter(command);
DataSet ds = new DataSet();
// Open Connection
command.Connection.Open();
// Populate
da.Fill(ds);
// Dispose of the adapter
if (da != null)
{
da.Dispose();
}
// If you do not explicitly close the connection here, it will leak!
if (command.Connection.State == ConnectionState.Open)
{
command.Connection.Close();
}
...
Now if I pass into the variable StoredProcName = "ThisProcDoesNotExists"
And run this peice of code. The CreateCommand nor da.Fill through an error message. Why is this. The only way I can tell it did not run was that it returns a dataset with 0 tables in it. But when investigating the error it is not appearant that the procedure does not exist.
EDIT
Upon further investigation
command.Connection.FireInfoMessageEventOnUserErrors = true;
is causeing the error to be surpressed into the InfoMessage Event
From BOL
When you set FireInfoMessageEventOnUserErrors to true, errors that were previously treated as exceptions are now handled as InfoMessage events. All events fire immediately and are handled by the event handler. If is FireInfoMessageEventOnUserErrors is set to false, then InfoMessage events are handled at the end of the procedure.
What I want is each print statement from Sql to create a new log record. Setting this property to false combines it as one big string. So if I leave the property set to true, now the question is can I discern a print message from an Error
ANOTHER EDIT
So now I have the code so that the flag is set to true and checking the error number in the method
void Connection_InfoMessage(object sender, SqlInfoMessageEventArgs e)
{
// These are not really errors unless the Number >0
// if Number = 0 that is a print message
foreach (SqlError sql in e.Errors)
{
if (sql.Number == 0)
{
Logger.WriteInfo("Sql Message",sql.Message);
}
else
{
// Whatever this was it was an error
throw new DataException(String.Format("Message={0},Line={1},Number={2},State{3}", sql.Message, sql.LineNumber, sql.Number, sql.State));
}
}
}
The issue now that when I throw the error it does not bubble up to the statement that made the call or even the error handler that is above that. It just bombs out on that line
The populate looks like
// Populate
try
{
da.Fill(ds);
}
catch (Exception e)
{
throw new Exception(e.Message, e);
}
Now even though I see the calling codes and methods still in the Call Stack, this exception does not seem to bubble up?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我花了一些时间,得出的结论是 InfoMessageHandler 不是在执行命令对象的范围内引发的。因此,您在事件中引发的异常不会冒泡到命令对象的方法。它必须在不同的线程中执行。
我假设您使用的是 Visual Studio 2008,因为我能够在该环境中准确地重现您的问题。当我将代码迁移到 Visual Studio 2010 时,仍然使用框架 3.5,新的 IDE 捕获自定义异常,但我无法找出捕获代码中异常的简单方法。 Visual Studio 2010 调试器在调试多线程方面表现得更好。
如果要捕获此事件中的异常,则必须编写可以跟踪线程异常的代码。
I spent some time on this and came to the conclusion that the InfoMessageHandler is not raised within the scope of the executing command object. Therefore, exceptions that you throw within the event will not bubble up to command object's method. It must be executing in a different thread.
I assume you are using Visual Studio 2008, because I was able to reproduce your issue exactly in that environment. When I migrated the code to Visual Studio 2010, still using framework 3.5, the new IDE catches the custom exceptions, but I wasn't able to figure out an easy way to catch the exceptions in code. The Visual Studio 2010 debugger is much better at debugging multiple threads.
If you want to catch exceptions from this event, you will have to write code that can track thread exceptions.