我碰到这个教程,以了解如何与GO语句执行SQL脚本。
现在,我想知道我能做得到的消息TAB的输出。
随着几个GO语句,输出会是这样:
1行受影响
912行受影响
...
但server.ConnectionContext.ExecuteNonQuery()只能返回一个int,而我需要的所有文本。 但如果是在查询的某些部分有些错误,应该把该还的输出。 任何帮助,将不胜感激。
我碰到这个教程,以了解如何与GO语句执行SQL脚本。
现在,我想知道我能做得到的消息TAB的输出。
随着几个GO语句,输出会是这样:
1行受影响
912行受影响
...
但server.ConnectionContext.ExecuteNonQuery()只能返回一个int,而我需要的所有文本。 但如果是在查询的某些部分有些错误,应该把该还的输出。 任何帮助,将不胜感激。
最简单的事情是可能只打印你回来了数量ExecuteNonQuery
:
int rowsAffected = server.ConnectionContext.ExecuteNonQuery(/* ... */);
if (rowsAffected != -1)
{
Console.WriteLine("{0} rows affected.", rowsAffected);
}
这应该工作,但不会兑现SET NOCOUNT
当前会话/范围的设置。
否则你会像你那样做将与“普通” ADO.NET做。 不要使用ServerConnection.ExecuteNonQuery()
的方法,但创建SqlCommand
通过访问底层对象SqlConnection
对象。 在那个订阅StatementCompleted
事件。
using (SqlCommand command = server.ConnectionContext.SqlConnectionObject.CreateCommand())
{
// Set other properties for "command", like StatementText, etc.
command.StatementCompleted += (s, e) => {
Console.WriteLine("{0} row(s) affected.", e.RecordCount);
};
command.ExecuteNonQuery();
}
使用StatementCompleted
(而是说,手动打印该值ExecuteNonQuery()
返回)有它的工作原理完全一样SSMS或SQLCMD.EXE将受益:
SET NOCOUNT ON
设置,它不会在所有调用。 SET NOCOUNT OFF
设置,它会被称为一个批次内的每个语句。 (边栏:它看起来像StatementCompleted
正是当有关TDS协议谈判DONE_IN_PROC
提到事件;见备注 MSDN上的SET NOCOUNT命令。)
就个人而言,我已经使用在SQLCMD.EXE我自己的“克隆”成功的这种做法。
更新 :应该指出的是,这种方法(当然)需要您手动在拆分输入脚本/报表GO
分离器,因为你回来使用SqlCommand.Execute*()
不能同时处理多批。 对于这一点,可以有多种选择:
GO
(警告: GO
可以称为像GO 5
,例如,以执行前一批5次)。 我选择后者选项,这是相当一些工作,因为它不是非常有据可查和例子并不多见(google了一下,你会发现一些东西,或者使用反射镜看到SMO组件如何使用这些类) 。
使用的好处(也许负担) ManagedBatchParser
是,它还将解析T-SQL脚本的所有其他结构(用于SQLCMD.EXE
)为您。 包括: :setvar
, :connect
, :quit
等不必执行相应的ICommandExecutor
会员,如果你的脚本不使用它们,当然。 不过,别忘了,你会可能无法执行“乱”的脚本。
嗯,是这样做就把你。 从如何打印“......受影响的行”的事实,这是不平凡的一个强大的和一般的方式做了“简单问题”(给出所需的后台工作)。 因人而异,好运气。
更新上ManagedBatchParser用法
似乎是有关如何实现没有好documenation或例如IBatchSource
,这里是我跟去了。
internal abstract class BatchSource : IBatchSource
{
private string m_content;
public void Populate()
{
m_content = GetContent();
}
public void Reset()
{
m_content = null;
}
protected abstract string GetContent();
public ParserAction GetMoreData(ref string str)
{
str = null;
if (m_content != null)
{
str = m_content;
m_content = null;
}
return ParserAction.Continue;
}
}
internal class FileBatchSource : BatchSource
{
private readonly string m_fileName;
public FileBatchSource(string fileName)
{
m_fileName = fileName;
}
protected override string GetContent()
{
return File.ReadAllText(m_fileName);
}
}
internal class StatementBatchSource : BatchSource
{
private readonly string m_statement;
public StatementBatchSource(string statement)
{
m_statement = statement;
}
protected override string GetContent()
{
return m_statement;
}
}
这是你将如何使用它:
var source = new StatementBatchSource("SELECT GETUTCDATE()");
source.Populate();
var parser = new Parser();
parser.SetBatchSource(source);
/* other parser.Set*() calls */
parser.Parse();
需要注意的是这两种实现,无论是直接声明( StatementBatchSource
)或文件( FileBatchSource
)有他们阅读全文一次到内存的问题。 我有一种情况是炸毁,具有生成的gazillions一个巨大的(!)脚本INSERT
语句。 尽管我不认为这是一个实际问题, SQLCMD.EXE
可以处理它。 但对我的生活,我无法弄清楚究竟如何,则需要形成返回块IBatchParser.GetContent()
这样分析器仍然能够与他们合作(它看起来像他们将需要完整的语句,这会有点击败解析的目的摆在首位...)。