2018年1月24日 星期三

【.NET Core】使用SQLite

使用版本:

  • Visual Studio 2017 ver: 15.5.1
  •  .NET Core 2.0
  •  System.Data.SQLite.Core ver: 1.0.106


參考資料:




1. 到官網下載SQLite (可省略)
  到這邊(不放心的可以到官網點Download)選已經build過的,或者取得原始碼再自己編譯
我比較懶又沒特別需求,打算再Window x64的環境跑,所以是選Download的「Precompiled Binaries for Windows」→「sqlite-dll-win64-x64-3220000.zip」

  如果打算用cmd去操作,還要可以下載「sqlite-tools-win32-x86-3220000」,這樣就能在cmd中透過指定建立db或進行管理,但是... 值在太辛苦了,所以靠第三方工具吧!


2. 下載第三方工具 (有其他管理工具也可省略)
  問了Google大神,他給我 DB Browser for SQLite ,就來試用看看了
總之,進入網頁後,在右邊找到我要的版本「Download 64-bit Window .exe」,下載後就一路下一步到底,然後執行(如果看到黑色的cmd閃出來又消失,是正常的別緊張)。

  它將sqlite3的指令都圖形化,上手並不難,如果已經有現成的DB就選「打開資料庫」,而我什麼都沒有,所以是選「新建資料庫」。點下去後它會彈出Dialog要選新增在哪個位置,打上檔名後「存檔」。

  接著試「編輯資料表定義」,它雖然有Advanced項目,但Rowid各人強烈建議要有,而我也不是建立Temp table,兩個都維持未勾選狀態就好。如果熟悉語法能直接在下面打,但要注意... SQL語法不完全相容喔!,避免敲錯字,我還是點「加入欄位」,接著試需求將「名稱、類型、非空(not null)、PK、AI(自動增值)、U(唯一值)、預設(Default)、檢查()、Foreign Key」設定完,就可以點「OK」。

    只是測試...我只建了三個欄位,自動產生的語法如下:
    CREATE TABLE `` (
     `id` INTEGER PRIMARY KEY AUTOINCREMENT,
     `name` TEXT NOT NULL,
     `comment` TEXT
    );

簡單說一下各頁籤用圖

  1. Database Structure: 想查Table屬性, 有哪些View(視圖), 異動Table都是在這
  2. Browse Data: 這是異動特定Table的內容,可以增減編輯Rows。「過濾」其實就類似『WHERE xxx LIKE '%ooo%'』;Table的下拉選單可以切換;要增加row就點「新建記錄」,反之則「刪除記錄」;要編輯資料就點一下那欄位後直接輸入。
  3. Edit Pragmas: 暫時用不到,所以pass
  4. Excute SQL: 直接使用SQL語法(大致上能用,但強烈建議參閱下方的連結),一樣能使用F5來Execute

最後當然少不了存檔!  雖然關閉時會跳提醒,問要不要儲存變更,但也能夠主動儲存的!
Write Changes: 寫入改變。會把寫在Memory中的資料(也就是未儲存的變更),寫到檔案中
Revert Change: 復原改變。放棄Memory中的資料(不儲存變更且恢復原狀),重讀檔案

2018/1/28: 不過Import和Export的方便性不夠,後來我又找了「SQLite Studio」來用

3. 正片終於開始的用C#存取 *.db

※強烈建議在NuGet中下載 System.Data.SQlite.Core 。因為用 Microsoft.Data.Sqlite 會非常的辛苦(DataTable無法簡單轉移,只有Reader沒有Adpater等,而且對IReader的支援性很差,會有Complier能過,實際執行卻會跳Exception的情況)


public IActionResult Index()
{
      //個人習慣會在一開始就開變數,可以無視
      string str = string.Empty;
      List _str = new List();

      //這裡才是SQLite重點
      //將Data Source指到檔案位置
      //用Directory.GetCurrentDirectory()可以簡易的取得根目錄
      string path = @"Data Source = "
            + Directory.GetCurrentDirectory()  
            + @"\Areas\Event\Data\TestBrowser.db"; 
      //進行連線,用using可以避免忘了釋放
      using (SQLiteConnection conn = new SQLiteConnection(path)) 
      {
          //再來這邊的步驟跟操作其他DB很像,就是建立Command,然後連入合法的SQL語句,再Open連線
          string sql = "select * from FastTest"; 
          SQLiteCommand cmd = new SQLiteCommand(sql,conn);
          conn.Open();

          //連線有Open後,就能用Reader去讀取Query結果
          SQLiteDataReader reader = cmd.ExecuteReader();

          //這是用Microsoft.Data.Sqlite時的寫法,只能這樣先推到儲存資料再另外處理。
          while (reader.Read())
          {
              _str.Add(reader["name"].ToString());
          }

          //改用System.Data.SQLite後,要轉DataTable只要用Load()就行了
          DataTable dt = new DataTable();
          dt.Load(reader);

          //如果是用adapter跟DataSet就更簡單了
          SQLiteDataAdapter adapter = new SQLiteDataAdapter(sql, conn); //似乎不能直接用cmd? 會有Exception
          DataSet ds = new DataSet();
          adapter.Fill(ds, "FirstTable"); //用 .Fill(ds) 就夠了,要重新命名TableName才需要放第二個參數
          //接著只要 ds.Tables[0] 就能取出DataTable (當然... DataSet不止能這樣用)
      }

      //這裡則是用來看接到哪些資料, reader示範, DataTable的部分預計要跟vue配合,那時再說 XD
      str = string.Join(", ", _str.ToArray());
      ViewBag.DBdata = str;
      return View();
}

這樣之前在 *.cshtml 中寫 @ViewBag.DBdata; 的位置,就會顯示SQLite中撈出來的結果了!


想把DB帶著走,去除微軟的Access,我只想到SQLite
與其說心得分享,更像是純日記
重0開始弄SQLite已經是第二次了,卻忘的一乾二淨,為了省掉不知哪時會遇到的第3次而留下的記錄,就直接記錄我的操作

由於可能會有多人線上操作(給管理者用,尖峰約3~7人),所以也查了一下這部分,SQLite似乎只有「寫入」的瞬間會Lock檔案(畢竟是以檔案的方式儲存),而官方說法是100K/每日的點擊量完全可以承受(資料如果不複雜,400K/日也能行),看起來應該勘用。現在我只擔心using的回收機制太慢,改天再試試看要主動Close,還是等using釋放資源。

如果有更好的選擇還請指點!

補充資料:
(英文)SQLite官網:https://sqlite.org
(英文)SQLite的型別及轉換參考:http://www.sqlite.org/datatype3.html
(簡中)菜鸟教程 - SQLite 数据类型 :http://www.runoob.com/sqlite/sqlite-data-types.html

2017年8月5日 星期六

【MVC】在IIS7.5中設定環境給MVC用

只是將ASP.NET WebForm發布到IIS時還挺順利的
我只有在設定讓區網內的其他電腦可以連到虛擬機中的IIS卡過,而且這問題主因在不熟VMWare,而不是IIS
但MVC光是這IIS這邊就麻煩不少了

測試環境: win7 pro & IIS 7.5
測試網站: 微軟提供的教學範本



前面的起手式與傳統網站相同,都是要開啟Windows功能 (IIS因為安全性關係,預設關閉)


1. 開啟「控制台」找到「開啟或關閉Windows 功能」,參考下圖將功能開啟
  • Web 管理工具 -> IIS管理主控台 (非必要,但強烈建議裝)
  • www服務 -> 應用程式開發功能 -> ASP.NET (必要)
  • www服務 -> 應用程式開發功能 -> ISAPI 篩選器 (必要)
  • www服務 -> 應用程式開發功能 -> ISAPI 擴充程式 (必要)



2. (不見得需要做)如果IIS比.NET Framework後裝,就要接著開啟cmd執行註冊(依OS選擇註冊方式),讓他跑一下(數秒而已)

  • OS為32bit「C:/Windows/Microsoft.NET/Framework/v4.0.30319/aspnet_regiis.exe -i」
  • OS為64bit「C:/Windows/Microsoft.NET/Framework64/v4.0.30319/aspnet_regiis.exe -i」
(大部分的開發環境可能都是後裝,除非一開始就確定要當AP Server)

3. 然後就能在「開始」輸入「IIS」把主控台叫出來
 



如果是WebForm,到這裡就可以開始Publish網頁跟指定路徑了,但是佈署mvc比普通網站更麻煩,所以從這裡開始要多設定一些!

4. 開啟「ISAPI及CGI限制」的功能視窗
 


4.1 然後將「限制」改為「允許」 (最低限度是啟動第三列的64bit就能執行了。)
 


5. 然後就可以Publish專案啦,方法可以參考這影片,這裡不細說。畢竟都要設定IIS了,應該... 不會不知道怎麼publish基本款的網站吧?
https://www.youtube.com/watch?v=FzwcD_XQ4ko


6. 回到IIS主控台,對「站台」右鍵 -> 點「新增網站」 然後參考下面設定

圖片太小的話,可以開新分頁去看
※應用程式集區就是「步驟4.1中『允許』的那個程式集區

※我偏好使用不同的連接port去設定網站,這樣就不用記一堆IP,但是注意要那條port有沒有被防火牆鎖起來就是了
 

7. 如果是VS預設的MVC範本,到此就可以執行了
用「瀏覽」或者直接在瀏覽器輸入網址



參考來源:iis部署asp.net mvc網站出錯的解決方法 




如果網站有使用到編譯為32bit的DLL,就還要多設定一小段

Extra 1. 看是哪個站台有需要用到32bit的DLL,對它指定的「應用程式集區」右鍵→點「進階設定



Extra 2. 將「啟用32位元應用程式」設定為True就可以了。
當然也能為了它新增個別的程式集區,但是這步一定要做!


Extra 3. 保險起見,將網站停止後,再啟動吧。

參考來源:在Windows7 x64的IIS使用32bit的odbc driver 

2017年7月30日 星期日

【WPF】執行背景工作時,讓畫面不會看起來像卡住


只是想在WPF中使用熟悉的Process Bar,那就別花時間看這篇了
到 youtube去搜尋比較快

這篇不會提到Process Bar,雖然同樣的原理也能用在Process Bar,甚至是自訂的任何進度條。這篇還順便迴避某些書中範例無法回傳string的問題。

原因是WPF畫面的呈現和背景工作是分開的
當程式在忙碌時,畫面會乖乖的一直等背景工作跟他說OK才刷新
(圖片看起來會動,就是因為畫面不斷的刷新喔!)

想像影片前半段,希望能夠「圖片會動、文字會逐項目顯示」,那就需要用到
Async 和 Await
來寫出非同步程式,這樣畫面就不會等到海枯石爛了!
沒聽過「非同步, await, async」的也不用擔心,可以先理解差異,有興趣再找資料吧

●先來一段失敗的程式碼

        private void test_Click(object sender, RoutedEventArgs e)
        {
            //沒使用async & await
            showLog.Text = "轉檔開始(2秒/個)\r\n";
            for (int i = 0; i < 3; i++)
            {
                showLog.Text += "開始第" + (int)(i + 1) + "個轉檔...";
                Thread.Sleep(2000); //模擬轉檔時會停頓的時間
                showLog.Text += "End\r\n";
            }
            showLog.Text += "轉檔全部結束\r\n";
        }
●然後這是成功的程式碼

        private async void test_Click(object sender, RoutedEventArgs e)
        {
            //使用async & await
            showLog.Text = "轉檔開始(2秒/個)\r\n";
            for (int i = 0; i < 3; i++)
            {
                showLog.Text += "開始第" + (int)(i + 1) + "個轉檔...";
                showLog.Text += await ConvertFile("End\r\n");
            }
            showLog.Text += "轉檔全部結束\r\n";
        }

        public Task<string> ConvertFile(string str)
        {
            return Task.Factory.StartNew(() => this._ConvertFile(str));
        }

        public string _ConvertFile(string para1) {
            Thread.Sleep(2000); //模擬轉檔時會停頓的時間
            return para1;
        }

知道怎麼套用await和async,讓畫面不會卡住了嗎?
還是不懂的話,再繼續往下看吧


1. 在可能會執行到需要花時間,但前後想加上其他程式碼的方法(method)的宣告加上「async」,這樣之後要加的await才有作用。只加async卻沒加await,也不會有作用的喔!
before:
private void test_Click(object sender, RoutedEventArgs e){...}
after:
private async void test_Click(object sender, RoutedEventArgs e){...}
2. 宣告一個回傳「數值或字串」的方法 (※不見得要寫成能傳參數,只寫"public string _ConverFile()"也行) 
before:
private async void test_Click(object sender, RoutedEventArgs e){
        ...
        Thread.Sleep(2000); //模擬轉檔時會停頓的時間
        ...
}
after:
private async void test_Click(object sender, RoutedEventArgs e){
        ...
        //Thread.Sleep(2000); //將要背景執行的function搬出這個method
        ...
}
public string _ConvertFile(string para1) {
    Thread.Sleep(2000); //模擬轉檔時會停頓的時間
    return para1;
}
3. 再宣告一個Task,要利用它awaitable的特性,同時利用方便的「Factory.StartNew(...)」來快速的建立與啟動新Task (※也可以不丟參數,直接寫成 "public Task ConverFile()")  
public Task ConvertFile(string str)
{
    return Task.Factory.StartNew(() => "action");
}
4. 將「步驟2」跟「步驟3」結合
public Task ConvertFile(string str)
{
    return Task.Factory.StartNew(() => this._ConvertFile(str+"只是個丟參數的地方")); 
}

5. 將組好的task放在method中使用,記得要加上「await
private async void test_Click(object sender, RoutedEventArgs e){
        ...
        showLog.Text += await ConvertFile("End\r\n"); //取代原本會拖時間的function
        ...
}

然後就...完成! 可以執行程式,體驗差異了!

【延伸】
有興趣的可以試試看:
1. 只加Async,卻沒用Await,是不是也能成功?
2. 只是把工作丟給Task,卻沒有用Async和Await,是不是也能成功?

如果好奇「await和async」的原理,可以看MSDN的介紹
使用Async 和 Await 設計非同步程式 (C# 和 Visual Basic)
然後找到段落「非同步方法中執行了哪些工作」,會有詳細的執行流程
圖看一次不懂沒關係,不需要刻意去記住,用多就會理解了

2017年3月10日 星期五

【C#】跨視窗傳遞集合

我預計的期望是:
  在「視窗A」點按鈕(Button) → 彈出「視窗B」→ 將「視窗B」更改後的數值回傳

由於「視窗B」的設定不是只有一項,要回傳的話一定是陣列(Array)或集合(Collections)
好處是彼此的變數並不直接干涉,不用因為改了變數名,另一個也要跟著改。

※我用的是WPF,會跟WinForm有一點差距,但是概念差不多。偏基礎的部分,下面介紹就省略了,畢竟需要跨視窗還很在意修飾詞(public, private...)的人,看廢話也覺得煩吧。


視窗A - MainWindow
        private Dictionary<stringstring> SetDic = new Dictionary<stringstring>();
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            SettingWindow sw = new SettingWindow(SetDic);
            if (sw.ShowDialog() == true//從設定中取值
                SetDic=sw.ApplySetting();
         }

視窗A的程式碼主要是
第一列:建立Dictionary的集合「SetDic」,作為接收與後續利用
第四列:在事件中用實做視窗B「SettingWindow」,視窗B的建構式看下面
第五、六列:如果在視窗B有點「確定」之類的,那就會執行「SettingWindow」中寫好的方法,將回傳的集合賦值給「SetDic」

視窗B - SettingWindow
    public partial class SettingWindow
    {
        private Dictionary<stringstring> _SetDic;
        public SettingWindow(Dictionary<stringstring> _SetDic)
        {
            //(不重要,中略)
            _SetDic=SetDic;
        }
        private void Apply_Click(object sender, RoutedEventArgs e)
        {
            //(不重要,中略)
            this.DialogResult = true;
            this.Close();
        }
        internal Dictionary<stringstring> ApplySetting() {
            //(不重要,中略)
            return _SetDic;
        }
    }

視窗B就是重頭戲了,分成
第一列:可以看到這個視窗的類別名稱是「SettingWIndow」
第三列:建立一個用來暫存從視窗A丟過來的集合「_SetDic」
第四~八列:由於要接視窗A丟過來的「SetDic」,所以在寫建構式時,要定義參數型別。然後在將接到「SetDic」賦予給「_SetDic」
第九~十四列:這個是點「確定」時,會觸發的事件。重點在第十三列與第十四列的「this.DialogResult = true; this.Close();」,功能分別是「要讓視窗A第五列的IF判斷能成功觸發、關閉視窗B」
第十五~十八列:寫一個會回傳數值的方法,把在視窗B變更過的「_SetDic」回頭賦予給「SetDic」


2016年6月29日 星期三

[WPF]使用App.config來集中管理連線字串(ConnectionString)

因為內部的程式(VB6, winForm)要整個翻新,所以從ASP.net被拉回寫視窗程式
想說既然都要翻新,那乾脆整個框架一起翻新就用了M$支援度比較高的WPF
當然也不意外地要跟資料庫溝通,也就整個從Access換去SQL server

---------好,上面都不是重點, 只是緣由-----------------------------------

既然要跟資料庫結合,一定少不了「連線字串」
因為我都是ADO.net去寫,對於連線字串的依賴相當大
至於每次都要重寫但不易管理的方法就不提了,書本上都有
我這邊是寫個人偏好的集中管理 :D

1. 加入參考「System.Configuration.dll」
2. 在App.config中的<configuration>...</configuration>中加上

<connectionStrings>    
    <add name="DBconnStr" connectionString="要使用連線字串" />
</connectionStrings>

3. 在要設定連線字串的地方用以下進行代入
C#
string connStr = ConfigurationManager.ConnectionStrings["DBconnStr"].ConnectionString;
VB

Dim connStr As Stringction(Configuration.ConnfigurationManager.ConnectionStrings("DBconnStr").ConnectionString

----------------------------
如果直接 new SqlConnection, 可參考下列寫法

SqlConnection connstr = new SqlConnection(ConfigurationManager.ConnectionStrings["AL_connstr"].ConnectionString)

2016年5月17日 星期二

[LINQ]在LINQPad中使用LinqToExcel(如何引入參考與Namespaces)

LINQPad是一個可以快速檢視LINQ查詢結果的工具(而且是麻雀雖小但五臟俱全)
不像在VS中還需要特別寫顯示的畫面,對於Demo來說相當方便
這篇文章只是從零到在LINQPad使用LinqToExcel的教學文
重點在於「如何引入參考和命名空間」
LINQPad的詳細使用可以找google小姐

LinqToExcel對針對只「讀」的資料而言,比NPOIOpenXML更佳的選擇

LINQPad版本(官網下載的FREE)v4.50.00
LinqToExcel版本(NuGet抓取)v1.10.1 

Step1: 取得LINQPad


不喜歡安裝的,可以點紅框處。至於選LINQPad 5 還是LINQPad 4 則取決於用的.NET Framework版本

下載後,解壓縮在尬意的位置就可以了,然後點「LINQPad.exe」執行
打開LINQPad後,畫面長這個樣子

Step2: LINQPad環境設定

要使用LinqToExcel前,需要將DLLLINQPad認識。(加入參考與命名空間)
點工具列的「Query」→「Query Peoperties
在「Additional Reference」的頁籤中,利用「Browse...」將已經抓好的LinqToExcel相關DLL如圖所需添加(Name欄位才有參考價值)

再換到「Additional Namespace Imports」頁籤中添加命名空間
如果不知道要打什麼或是擔心打錯的,點「Pick from assemblies
右側就會自動產生相應的命名空間,需要的再點「< Add Selected Namespaces」添加
最後,當然就是點OK

Step 3:Query

Language切換到「C# Program 」後 (Language詳細請參閱:LINQPad: The Ultimate .NET Scratchpad)
在輸入區打上下方語法後,Excute(F5)
----------------------------------------------------------------------------------------
void Main()
{
    var fileName=System.IO.Path.Combine(@"E:\備份\2016年度","SOP文件總攬.xlsx");
    var excelFile=new ExcelQueryFactory(fileName);
   
    var excel=excelFile.Worksheet(1); //亦可輸入工作表名 excelFile.Worksheet(“工作表1”)
    foreach (var element in excel)
    {
        element.Dump();
        "".Dump();
    }
}
----------------------------------------------------------------------------------------

然後你就得到它了

2016年2月22日 星期一

[豆知識]在網頁中貼上有上色的VS相關語法

沒技術量的筆記

以往在網頁或Blog中要貼語法又要有顏色時,不外乎這幾種選擇

  • 再自己手動上色
  • 使用網路上的語法上色器
  • 用js進行上色
  • 貼圖(需大量解說的才用方法, 畢竟處理相對耗時)


最近發現一個更簡單, 非常適合懶人的方法

  1. 將在VS中複製的語法,貼上Word
  2. 然後再從Word中複製,轉貼到網頁或Blog


當然這作法去看html原始碼時,某些有強迫症或潔癖的人會吐血(我有一點)
把很多不必要的Code都包進來了
不過當我文章大致完稿,不再去弄排版只差程式碼上色時
就會這樣使用

如果各位有更好的點子,也請多多指教了。