C# C脚本在运行下一步之前未完成SQL查询
我有一个c脚本,它作为更大代码的一部分运行。它应该执行一个sql脚本,然后通过SFTP连接发送生成的.csv文件 问题在于,查询似乎是在执行完查询之前发送数据的。在我的程序进行下一步之前,是否有办法确保查询已完成 下面是这篇文章的SQL部分的代码C# C脚本在运行下一步之前未完成SQL查询,c#,tableadapter,C#,Tableadapter,我有一个c脚本,它作为更大代码的一部分运行。它应该执行一个sql脚本,然后通过SFTP连接发送生成的.csv文件 问题在于,查询似乎是在执行完查询之前发送数据的。在我的程序进行下一步之前,是否有办法确保查询已完成 下面是这篇文章的SQL部分的代码 using System; using System.Data; using System.Data.SqlClient; using System.Configuration; namespace SQLtoCSV { static cla
using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
namespace SQLtoCSV
{
static class SQL
{
public static DataTable GetData(string strQuery)
{
var cmd = new SqlCommand(strQuery);
var dt = new DataTable();
var strConnString = ConfigurationManager.ConnectionStrings["RSConString"].ConnectionString;
Logger.WriteLog("Used RS connection string: {0}", strConnString);
var con = new SqlConnection(strConnString);
var sda = new SqlDataAdapter();
cmd.CommandType = CommandType.Text;
cmd.CommandTimeout = Convert.ToInt32(ConfigurationManager.AppSettings["RSTimeout"]);
cmd.Connection = con;
try
{
con.Open();
sda.SelectCommand = cmd;
sda.Fill(dt);
return dt;
}
catch (Exception ex)
{
Logger.WriteLog("SQL GetData trown exception, see next entry.");
Logger.WriteLog(ex);
return null;
}
finally
{
con.Close();
sda.Dispose();
con.Dispose();
}
}
}
}
这里是主控制流
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.IO;
namespace SQLtoCSV
{
class Program
{
static void Main(string[] args)
{
try
{
string sourceDirectory = ConfigurationManager.AppSettings["LocalSQLdirectory"].ToString();
List<string> txtFiles = Directory.EnumerateFiles(sourceDirectory, "*.sql", SearchOption.AllDirectories).ToList();
Logger.WriteLog("Found {0} SQL files in local dir '{1}'.", txtFiles.Count, sourceDirectory);
foreach (string currentFile in txtFiles)
{
string strSql = File.ReadAllText(currentFile);
Logger.WriteLog("Executing '{0}'...", currentFile);
var dtTable = SQL.GetData(strSql);
Logger.WriteLog("Done.");
var tmpFile = currentFile + ".tmp";
TableToCSV.ConvertDtTableToCSV(dtTable, tmpFile);
var name = Path.GetFileNameWithoutExtension(currentFile);
SFTP.upload(tmpFile, name);
File.Delete(tmpFile);
}
}
catch (Exception ex)
{
Exception exMail = null;
Logger.WriteLog("The main app trown exception, see next entry");
try
{
var msg = "CSV to SQL application thrown exception: \r\n" +
"\tSource: " + ex.Source + "\r\n" +
"\tMessage: " + ex.Message + "\r\n" +
"Stack: \r\n" + ex.StackTrace + "\r\n";
if (ex.InnerException != null)
{
msg += "Inner exception: \r\n" +
"\tSource: " + ex.InnerException.Source + "\r\n" +
"\tMessage: " + ex.InnerException.Message + "\r\n" +
"\tStack: " + ex.InnerException.StackTrace + "\r\n";
}
MailHelper.Send_Mail(msg, "SQL to CSV error");
}
catch(Exception ex2) {
exMail = ex2;
}
Logger.WriteLog(ex);
if (exMail != null)
{
Logger.WriteLog("Cannot send a mail, see next entry");
Logger.WriteLog(exMail);
}
}
}
}
}
好的,CSV部分是您的问题。默认情况下,StreamWriter是缓冲的,因此您的最后一块数据很可能不会写入磁盘。添加sw.Flush;在您结束像这样使用语句之前:
public static void ConvertDtTableToCSV(DataTable dt, string filePath)
{
string tempPath = System.IO.Path.GetTempPath();
using (var sw = new StreamWriter(filePath, false, Encoding.UTF8))
{
var columnNames = dt.Columns.Cast<DataColumn>().Select(column => column.ColumnName);
sw.WriteLine(string.Join(",", columnNames));
foreach (DataRow row in dt.Rows)
{
IEnumerable<string> fields = row.ItemArray.Select(field => /*string.Concat("\"", */field.ToString()/*.Replace("\"", "\"\""), "\"")*/);
sw.WriteLine(string.Join(",", fields));
}
sw.Flush();
}
}
我不想这么说,但是代码本身是正确的,尽管缺少flush部分。也就是说,问题出在配置文件上,导致数据从测试环境而不是生产环境中提取 由于两者的结果集通常是镜像的,因此发现它们之间存在细微的差异。我想这个故事的寓意是,如果你看到的是与你所看到的理论图景不相符的非常奇怪的结果,那么退一步,确保基础是正确的是值得的
感谢所有帮助过我的人 您看到了什么使您认为查询在执行之前发送了数据?是否有更多的代码可以准确地显示您看到的内容?例如,您提到的下一步是哪行代码?保存数据的部分在哪里?你的意思是sda.Filldt在返回dt时没有完成吗?我将把主控制流发布到原始comment.G_P中。为了澄清,我怀疑脚本以某种方式切断了临时文件。我手动运行查询时得到的数据约为1gig;通过脚本发送的文件约占其中的20%。因此,要么是以更高效的格式保存,要么不是所有的数据都进入了文件。您是否调试了它,并在返回时检查了dtTable中的行数?我几乎更倾向于说,在您的代码中生成csv而不是SQL部分。遗憾的是,这让我得到了与之前截取文件相同的最终结果。这似乎是一个愚蠢的问题,但这可能是对tmp文件大小的限制,从而阻止所有数据进入吗?哦,等等,您是在查看temp文件还是FTP文件,以获取所看到的行数。你用什么FTP文件?我添加了SFTP部分,你可以看一下。我不认为我关于tmp文件大小的理论是正确的,因为我可以手动推到.tmp并获得正确的数据量。我们将删除临时文件的那一行注释掉并检查它。或者将其设置为在其他地方手动写出。不过,您的FTP代码也缺少刷新。
using System;
using System.Configuration;
using Renci.SshNet;
using System.IO;
namespace SQLtoCSV
{
static class SFTP
{
public static void upload(string tmpFile, string fileName)
{
try
{
var host = ConfigurationManager.AppSettings["SFTPhost"].ToString();
var port = Convert.ToInt32(ConfigurationManager.AppSettings["SFTPport"]);
var username = ConfigurationManager.AppSettings["SFTPuser"].ToString();
var password = ConfigurationManager.AppSettings["SFTPpassword"].ToString();
var workingdirectory = ConfigurationManager.AppSettings["SFTPdirectory"].ToString();
var fileExtension = ConfigurationManager.AppSettings["UploadedFileExtension"].ToString();
var timeout = Convert.ToInt32(ConfigurationManager.AppSettings["SFTPtimeout"]);
var timestamp = ConfigurationManager.AppSettings["SFTPtimestamp"].ToString();
fileName += DateTime.Now.ToString(timestamp) + ".csv";
using (var client = new SftpClient(host, port, username, password))
{
client.ConnectionInfo.Timeout = TimeSpan.FromSeconds(timeout);
client.Connect();
Logger.WriteLog("Connected to {0}", host);
client.ChangeDirectory(workingdirectory);
Logger.WriteLog("Changed directory to {0}", workingdirectory);
using (var fileStream = new FileStream(tmpFile, FileMode.Open))
{
Logger.WriteLog("Uploading {0} ({1:N0} bytes)", fileName, fileStream.Length);
// bypass Payload error large files
client.BufferSize = 4 * 1024;
client.UploadFile(fileStream, fileName);
}
}
Logger.WriteLog("The file '{0}' is uploaded");
}
catch(Exception ex)
{
Logger.WriteLog("The SFTP.upload function trown exception, see next entry");
Logger.WriteLog(ex);
throw;
}
}
private static Stream StreamFromString(string s)
{
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
writer.Write(s);
writer.Flush();
stream.Position = 0;
return stream;
}
}
}
public static void ConvertDtTableToCSV(DataTable dt, string filePath)
{
string tempPath = System.IO.Path.GetTempPath();
using (var sw = new StreamWriter(filePath, false, Encoding.UTF8))
{
var columnNames = dt.Columns.Cast<DataColumn>().Select(column => column.ColumnName);
sw.WriteLine(string.Join(",", columnNames));
foreach (DataRow row in dt.Rows)
{
IEnumerable<string> fields = row.ItemArray.Select(field => /*string.Concat("\"", */field.ToString()/*.Replace("\"", "\"\""), "\"")*/);
sw.WriteLine(string.Join(",", fields));
}
sw.Flush();
}
}