2013年4月24日 星期三

.net 連線至遠端firebird資料庫

看了文件, 說firebird的.Net data provider是不需要依靠firebird client的軟體, 我由codeproject下載的程式(由.Net存取firebird資料庫), 也是真的可以不安裝firebird任何軟體, 就可以正常執行。只是這個程式是使用Embedded模式的firebird資料庫。我想要試試連到遠端super server模式的firebird資料庫看看。
直接去修改它的連線字串, 改成指到遠端資料庫看看先。結果, 就是不行。試過幾次後, 我注意到這個程式的幾個問題:
1. 它使用.Net 2.0
2. 它使用的firebird data provider也是for 2.0

所以我決定另開一個專案, 並下載firebird data provider 3.0.2.0(最新)的版本, 並直接用firebird官網的範例程式來試看看。一開始也是連不上, 所以我把專案的target framework由4.0改成 2.0。

一跑, 程式報出firebird data provider所需要的.net framework版本太低, 我再由2.0改成3.0, 結果還是一樣, 改回4.0後, 才不再出現這個錯誤訊息。因此, 我可以推論, 這個firebird data provider是for .net framework 4.0使用的。這時, 再去看看firebird官網的下載網頁, 可以看到同樣一個3.0.2的data provider卻有如此多個不同下載連結, 想來是有不同用途(例如: for .net 2.0一包, for .net 4.0一包, 兩個都有的一包)才會如此!


那不是一開始使用.Net 4.0就是正確的嗎? 為什麼還是連不上呢? 所以才會先去用Flamerobin連連看, 結果是可以正常連的。那就只是連線字串的問題了, 此時想到把範例資料庫檔案移到比較好記的地方(路徑比較簡單g:\data\employee.fdb), 因為原來連線的範例資料庫放在很深的路徑(C:\Program Files\Firebird\Firebird_2_5\examples\empbuild\employee.fdb), 光是確認檔名路徑沒打錯, 就很累了。沒想到這樣一改, 就連上了。

那麼遠端的firebird資料庫也應該可以連的上了, 所以就再改一下連線字串:

請注意, 因為遠端為fedora機器, 所以路徑斜線不同於windows機器的表示方式。當然, 這次也很順利的連上了。

簡單結論:
1. 看起來, 使用不同的data provider和不同的firebird版本/類型, 可能有影響
2. 資料庫檔案的路徑可能不能太複雜(ps.主要是自己會打錯字)
3. provider的錯誤訊息, 還有改進空間(看到以下錯誤訊息通常表示資料庫檔名打錯或者是主機名稱打錯或者是SQL下錯或者是schema不對: 未處理的例外狀況: System.TypeLoadException: 無法從組件 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' 載入型別 'System.Runtime.CompilerServices.ExtensionAttribute'。但這通常表示你快要成功了!)

接著, 再測試ADO.NET provider-agnostic的寫法, 即使用generic ado.net class來寫存取資料庫的方法。
1. 主程式: ExecuteReaderExample.cs
using System;
using System.Data;
using System.Data.Common;
//using System.Data.SqlClient;
public class ExecuteReaderExample
{
   public static void Main(string[] args)
   {
      /* string source = "server=.\\sqlexpress;" +
                      "integrated security=SSPI;" +
                      "database=Northwind";
     
      SqlConnection conn = new SqlConnection(source); */
      if (args.Length == 0)
      {
        Console.WriteLine("Usage: ExecuteReaderExample.exe option ");
        Console.WriteLine("     option can be ");
        Console.WriteLine("        Northwind  ");
        Console.WriteLine("     or Mysql      ");
        return;
      }
       string select = "SELECT * FROM Country";
       DbConnection conn = Login.GetDatabaseConnection(args[0]);
      conn.Open();
      //SqlCommand cmd = new SqlCommand(select, conn);
      IDbCommand cmd = conn.CreateCommand();
      cmd.CommandText = select;
      //SqlDataReader reader = cmd.ExecuteReader();
      IDataReader reader = cmd.ExecuteReader();
      while(reader.Read())
      {
         Console.WriteLine("Contact: {0,-20} Company: {1}",
                            reader[0], reader[1]);
      }
      conn.Close();
   }
}

2. 其App.config檔: ExecuteReaderExample.exe.config

3. 輔助程式檔: login.cs
using System;
using System.Data.Common;
using System.Configuration;
public class Login
{
  public static DbConnection GetDatabaseConnection(string name)
  {
      ConnectionStringSettings settings =
        ConfigurationManager.ConnectionStrings[name];
      DbProviderFactory factory = DbProviderFactories.GetFactory(settings.ProviderName);
      DbConnection conn = factory.CreateConnection();
      conn.ConnectionString = settings.ConnectionString;
      return conn;
  }
}

4. 編譯程式檔: make.bat
csc /t:exe /debug+ /r:System.dll /r:System.Data.dll /r:MySql.Data.dll /r:FirebirdSql.Data.FirebirdClient.dll ExecuteReaderExample.cs ..\login.cs

5. custum data provider: MySql.Data.dll, FirebirdSql.Data.FirebirdClient.dll 放在和程式同一目錄

總共有以上5個部份:
1. 主程式, 只使用generic ado.net classd來寫程式, 以避免被單一資料庫梆住
2. 設定檔, 用來提供data provider的資訊
3. 輔助程式, 用來由設定檔取得data provider的相關資訊, 並在Runtime時能產生正確的資料庫連線物件。
4. 編譯程式檔, 因編譯的參數太多, 所以用這個檔來記
5. 因為不是內建的data provider, 所以放進來了

編譯結果, 是成功的。但是一執行, 就報出錯誤訊息:
未處理的例外狀況: System.ArgumentException: 找不到必要的 .Net Framework Data Provider。可能尚未安裝。

這個訊息很明確, 就是沒有裝好data provider, 這表示DbProviderFactories物件找data provider的方法, 應該不是只是簡單的在目前程式目錄下找xxx.dll這樣簡單而已。很有可能要將data provider 安裝在GAC, 要去machine.config檔加入一些說明等...(我不知道)
所以我之前只下載.7z檔的方式, 在這裡就會出問題。
我只好再去下載.msi的安裝檔, 並安裝之。此時, 再去跑程式, 就ok了。想來, .msi安裝程式幫我做了一些什麼事。
總之, Firebird的ado.net data provider是支持Factory pattern, 可以做到db agnostic的ado.net class 寫法的。而我這個範例程式, 已經試過sql server, mysql, firebird三種資料庫了。

後記: 後來, 將Firdbird Sqlhelper(由codeproject下載)的程式, 換成3.0.2.0的data provider(for .net 3.5), 並將target framework改成3.5後, 就可以在修改連線字串後, 成功的連接到遠端的firebird資料庫了。
張貼留言