接上一章,我們要創建一個commandline 應用程序,通過輸入參數,可以讓它去指定目錄讀取文件,並且導入數據庫
【設計】
在編寫這個程序之前,我們要想想這個程序都需要做什么?
1.讀取commandline 參數。一個目錄,taskid 和taskName 3個參數。
2.到指定目錄讀取csv/txt 文件,把csv/txt 轉成 DataTable (這里有兩種txt文件,trend 和bar)
3.去數據庫中查詢,如果當前taskid 沒有記錄則插入記錄。否則更新記錄。
根據上邊需要,我們需要創建如下類/方法:
點擊解決方案->Add new project->Console Application
命名為:ReportingSyncer。
proj 右鍵屬性,修改命名空間和程序集名稱,與前邊ReportingDBManager的前綴保持一致,即:CnBlogsDemos.ReportingSyncer
創建commandline 類:

namespace CnBlogsDemos.ReportingSyncer { using System; using System.Collections.Generic; using System.Linq; using System.Text; public class CommandLine { protected Dictionary<string, string> _command; protected string _defaultConfig; public string InputDir { get { if (_command.ContainsKey("input")) { return _command["input"]; } throw new Exception("The expected parameter /input:[directory] is missing!"); } } public string ConfigFilePath { get { if (_command.Keys.Contains("config")) { return _command["config"]; } return _defaultConfig; } } public string TaskID { get { if (_command.ContainsKey("taskid")) { return _command["taskid"]; } throw new Exception("The expected parameter /taskid:[id] is missing!"); } } public string TaskName { get { if (_command.ContainsKey("taskname")) { return _command["taskname"]; } throw new Exception("The expected parameter /taskname:[name] is missing!"); } } public CommandLine(string[] args) { ParseCommandLine(args); CheckMandatoryParameter(); } public virtual string PrintInputParameters() { StringBuilder sb = new StringBuilder(); sb.Append("Input Parameter:"); foreach (KeyValuePair<string, string> param in _command) { sb.Append(string.Format("/{0}:{1}\t", param.Key, param.Value)); } return sb.ToString(); } private void ParseCommandLine(string[] args) { if (0 == args.Length || (1 == args.Length && (args[0].Contains("?") || args[0].ToLower().Contains("help")))) { Prompt(); throw new ArgumentException(""); } _command = new Dictionary<string, string>(); try { foreach (string arg in args) { string[] param = arg.ToLower().Split(new char[] { ':' }, 2); _command.Add(param[0].Replace("/", ""), param[1]); } } catch (Exception e) { throw new ArgumentException(e.Message); } } protected virtual void CheckMandatoryParameter() { throw new NotImplementedException(); } protected virtual void Prompt() { throw new NotImplementedException(); } } }
創建DataSyncer類(主要的操作都在這),先空着。
修改Programs類:
using System; using CnBlogsDemos.ReportingSyncer; namespace ReportingSyncer { class Program { static int Main(string[] args) { int iRet = -1; try { CommandLine cmd = new CommandLine(args); DataSyncer ds = new DataSyncer(cmd); } catch (Exception e) { //TODO } return iRet; } } }
現在我們開始寫DataSyncer類了。
首先添加EF引用。由於剛才我們在上一個proj 引用過了。我們可以去c:\users\你的名字\documents\visual studio 2010\Projects\ReportingSyncer\packages\EntityFramework.4.3.1\lib\net40\EntityFramework.dll找。我的是64位機器。32位的話,應該忽略(X86)。
再添加項目引用-》ReportingDBManager,這樣我們才可以使用剛才的DbStoreContext類。
根據上邊類圖所示:
DataSyncer類如下,具體的地方可以看代碼注釋:
namespace CnBlogsDemos.ReportingSyncer { using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Data; using CnBlogsDemos.ReportingDBManager; public class DataSyncer { private CommandLine _cmd; public DataSyncer(CommandLine cmd) { // TODO: Complete member initialization this._cmd = cmd; } internal int RunInCommandLineMode() { int iRet = -1; int taskId = 0; string inputDir = _cmd.InputDir; string taskName = string.Empty; string type = string.Empty; //Get taskid int.TryParse(_cmd.TaskID, out taskId); // if after parsing ,task id still equals 0 ,return if (taskId.Equals(0)) { Console.WriteLine("taskid is invalid"); return -1; } // if input directory is not exist parsing return if (!Directory.Exists(inputDir)) { Console.WriteLine("input directory is not exist"); return -1; } else { //read files from input dir var files = Directory.GetFiles(inputDir); if (!files.Any()) { Console.WriteLine("there is not files under input directory"); return -1; } else { foreach (var file in files) { if (file.Contains("trend.txt")) { type = "trend"; InsertAnalysisData(file, taskId, taskName, type); } else if (file.Contains("bar.txt")) { type = "bar"; InsertAnalysisData(file, taskId, taskName, type); } } } } return iRet; } public void InsertAnalysisData(string filePath, int taskId, string taskName, string type) { if (File.Exists(filePath)) { if (type.Equals("bar", StringComparison.OrdinalIgnoreCase)) { var dataRows = this.GetTableFromCSV(filePath).AsEnumerable(); // 創建一個新的 dbstore context 實例 using (DbStoreContext dsc = new DbStoreContext()) { // 如果 Bars表 存在任何相同的TaskID,刪除相關記錄 if (dsc.Bars.Any(n => n.TaskID.Equals(taskId))) { foreach (var item in dsc.Bars.Where(n => n.TaskID.Equals(taskId))) { dsc.Bars.Remove(item); } } foreach (var row in dataRows) { // 注意 ,這個 row.Field<string>(index);中的index 對應我們csv/txt 文件中的數據列,索引從0開始 Bar b = new Bar(); b.KeyWord = row.Field<string>(0); b.B1Better = Convert.ToInt32(row.Field<string>(1)); b.Equal = Convert.ToInt32(row.Field<string>(2)); b.B2Better = Convert.ToInt32(row.Field<string>(3)); b.Winner = row.Field<string>(4); b.IsActive = true; b.type = type; b.TaskID = taskId; b.TaskName = taskName; dsc.Bars.Add(b); } //保存修改。EF會去執行插入數據到DB,默認開啟事務 dsc.SaveChanges(); } } else if (type.Equals("trend", StringComparison.OrdinalIgnoreCase)) { var tailWholePageTrendDataRows = this.GetTableFromCSV(filePath).AsEnumerable(); using (DbStoreContext dsc = new DbStoreContext()) { if (dsc.Trends.Any(n => n.TaskID.Equals(taskId))) { foreach (var item in dsc.Trends.Where(n => n.TaskID.Equals(taskId))) { dsc.Trends.Remove(item); } } foreach (var row in tailWholePageTrendDataRows) { // 注意 ,這個 row.Field<string>(index);中的index 對應我們csv/txt 文件中的數據列,索引從0開始 Trend t = new Trend(); t.id = Convert.ToInt32(row.Field<string>(0)); t.TaskID = taskId; t.Time = Convert.ToDateTime(row.Field<string>(3)); t.B1Better = Convert.ToInt32(row.Field<string>(4)); t.Equal = Convert.ToInt32(row.Field<string>(5)); t.B2Better = Convert.ToInt32(row.Field<string>(6)); t.UnCertain = Convert.ToInt32(row.Field<string>(7)); t.GrandTotal = Convert.ToInt32(row.Field<string>(8)); t.TaskName = taskName; t.IsActive = true; t.type = type; dsc.Trends.Add(t); } dsc.SaveChanges(); } } } } /// <summary> /// GetTableFromCSV file /// </summary> /// <param name="csvFilePath">file path</param> /// <returns>data table</returns> private DataTable GetTableFromCSV(string csvFilePath) { using (StreamReader sr = new StreamReader(csvFilePath)) { string line = sr.ReadLine(); if (!string.IsNullOrEmpty(line)) { string[] columns = line.Split('\t'); DataTable dt = new DataTable(); foreach (string columnName in columns) { dt.Columns.Add(columnName); } while ((line = sr.ReadLine()) != null) { DataRow dr = dt.NewRow(); string[] dataColumns = line.Split('\t'); dt.Rows.Add(dataColumns); } return dt; } throw new Exception(string.Format("File Content in {0} is empty", csvFilePath)); } } } }
倒數第二步:創建app.config。上篇文章說過。我們刪除了ReportingDBManager類庫中的app.config。
我們要在ReportingSyncer 類庫中添加一個app.config指定我們的連接字符串
<?xml version="1.0" encoding="utf-8"?> <configuration> <connectionStrings> <add name="ReportingDataBase" connectionString="Initial Catalog=DemoReportDB;data source=.;Integrated Security=SSPI;Trusted_Connection=Yes" providerName="System.Data.SqlClient" /> </connectionStrings> </configuration>
最后一步,創建測試數據。
讓我們創建一個文件夾E:\demos\reportingImprot。下邊包含2個txt文件:trend.txt 和 bar.txt
trend.txt:
id taskid taskname time b1 equal b2 uncertain grandtotal 0 1 task1 2012-6-27 200 300 280 220 1000
注意中間是tab分割。
bar.txt:
KeyWord B1Better Equal B2Better Winner 聯眾 2 0 3 B1 瘋狂倒計時 0 0 3 B2 張娜拉 0 1 2 B1 截圖軟件 1 0 1 B2
因為有漢字,請保存為unicode格式
為了方便模擬用戶輸入,我們可以預設commandline 參數:
右擊ReportingSyncer 項目屬性:debug-》Commandline arguments 輸入:/input:E:\demos\reportingImprot/taskid:5 /taskname:TestTask。
在實際使用時候可以用cmd找到你的bin目錄 執行release /debug 下的 exe文件。
例如 cmd-> c:
->cd e:\C:\Users\ricky\Documents\Visual Studio 2010\Projects\ReportingSyncer\ReportingSyncer\bin\Release reportingsyncer /input:E:\demos\reportingImprot/taskid:5 /taskname:TestTask
。
我們還是在debug 下試試吧。運行,也可以調試看看。
檢查本地數據庫。太神奇了吧?數據已經導進來了。
檢查一下表結構
好,這章就講到這里。
下一章會繼續介紹如何使用vs 創建report