C# 脚本在 运行 下一步之前未完成 SQL 查询
C# script not completing a SQL Query before running the next step
我有一个 c# 脚本 运行 作为更大代码的一部分。它应该执行 sql 脚本,然后通过 SFTP 连接发送生成的 .csv 文件。
问题是查询似乎在查询执行完成之前发送数据。有没有办法确保在我的程序执行下一步之前完成查询?
下面 SQL 部分的代码。
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);
}
}
}
}
}
TableToCSV 部分
using System.Collections.Generic;
using System.Linq;
using System.Data;
using System.Text;
using System.IO;
namespace SQLtoCSV
{
static class TableToCSV
{
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));
}
}
}
}
}
SFTP 部分
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;
}
}
}
好的,CSV 部分是你的问题。 StreamWriter
默认情况下会进行缓冲,因此您的最后一块数据很可能不会写入磁盘。在结束 using
语句之前添加 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();
}
}
不想这么说,但是代码本身是正确的,尽管缺少刷新部分。那就是说问题出在配置文件上,导致数据从测试环境而不是生产环境中提取。
由于两者的结果集通常是镜像的,因此发现了细微的差别。我想这个故事的寓意是,如果您看到与您所看到的理论图不符的非常奇怪的结果,那么退后一步并确保基础是正确的是值得的。
感谢所有提供帮助的人!
我有一个 c# 脚本 运行 作为更大代码的一部分。它应该执行 sql 脚本,然后通过 SFTP 连接发送生成的 .csv 文件。
问题是查询似乎在查询执行完成之前发送数据。有没有办法确保在我的程序执行下一步之前完成查询?
下面 SQL 部分的代码。
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);
}
}
}
}
}
TableToCSV 部分
using System.Collections.Generic;
using System.Linq;
using System.Data;
using System.Text;
using System.IO;
namespace SQLtoCSV
{
static class TableToCSV
{
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));
}
}
}
}
}
SFTP 部分
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;
}
}
}
好的,CSV 部分是你的问题。 StreamWriter
默认情况下会进行缓冲,因此您的最后一块数据很可能不会写入磁盘。在结束 using
语句之前添加 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();
}
}
不想这么说,但是代码本身是正确的,尽管缺少刷新部分。那就是说问题出在配置文件上,导致数据从测试环境而不是生产环境中提取。
由于两者的结果集通常是镜像的,因此发现了细微的差别。我想这个故事的寓意是,如果您看到与您所看到的理论图不符的非常奇怪的结果,那么退后一步并确保基础是正确的是值得的。
感谢所有提供帮助的人!