2010年5月26日 星期三

LINQ to Entities 的準則

使用 LINQ to entities 時,應該注意下面幾件事。

避免 ORM 的弱點

  • Bulk Loads:大量載入太多資料
  • 大量的更新:為了追蹤 entity 的狀態,會秏損效能及記憶體
  • 回傳大量entity 的查詢
  • 長時間的 ObjectContext

以上是 ORM 工具共通的毛病,如 LINQ to SQL, NHibernate。
因此,資料匯出入就不適合使用 LINQ to Entities ,除非是一筆一筆地處理。

增加效能

  • 改善查詢語法
  • 由 identity 欄位查詢單一 entity
  • 使用eager loading 及使用 Include 一次取得資料
  • 只讀取資料時,關閉物件的 tracking
  • 資料庫,考慮使用 snapshot isolation

結論

LINQ 使用了 delegate 來改善查詢語法,增加可讀性及生產力。但也因為這個原因,會讓效能變差。因此,在開發的策略必須:讓系統能運作,然後讓它變快。

2010年5月25日 星期二

Delete workitem in TFS 2010

在 TFS 2010 中刪除 workitem 和以往的 TFS 2008 不一樣。

原因是 workitem 的管理需求太大了,因此將 power tool 中的workitem 部份獨立出來,成為 witadmin。

因此,要刪除 workitem ,在 TFS 2010 中需下如下的指令

Usage: witadmin destroywi /collection:collectionurl /id:id [/noprompt]

Ex: witadmin destroywi /collection:http://tfs2010:8080/tfs/defaultcollection /id:8

2010年5月21日 星期五

免費的ebook for Virtualization R2

在虛擬化需求愈來愈高的時代,微軟也開始提供相關的免費電子書,以增加自己的市場。

書名:Understanding Microsoft Virtualization R2 Solutions

下載: XPS format herePDF format here.

2010年5月20日 星期四

連接 Visual Studio 2005 到 TFS 2010 的詳細步驟 (中文版)

上次提到了英文版的安裝。那繁體中文版呢?照著上次英文版的連結,下載檔案時改用繁中版的檔案,試著照做一次,會發現狀況不同於英文版,也就是說不work啦!

安裝

  1. 安裝 Visual Studio 2005 CHT
  2. 安裝 Team 總管 2005。
  3. 安裝 Visual Studio 2005 SP1
  4. 安裝 VSTS 2005 相容 2010 套件

注意!步驟2不能使用這裡的連結哦!安裝這個img 檔案,在「新增/移除程式」中看到的是 Team Explorer 2005 - ENU,也就是英文版。所以行不通也。這時只好到 MSDN Subscriptions 下載 Team Foundation Server 2005 繁中版,拿它裡面的Team 總管來安裝中文的 Team 總管 2005。

在安步驟34時,安裝程式會重複安裝兩次。必須讓安裝程式完整地安裝完畢,否則會無法連接 TFS 2010

例如在步驟3,雖然只點擊執行一次,但安裝程式會執行兩次,一次更新步驟1的 VS2005 為 VS2005 sp1,第二次則更新步驟2的 Team Explorer 2005 為Team Explorer 2005 sp1。故會安裝兩次。

相同地,步驟4也會安裝兩次,分別更新 VS2005 sp1 及 Team Explorer sp1,讓這兩個產品得以連接 TFS 2010。

設定

接下來,就可以設定 Team Foundation Server。使用 工具 \  連接到 Team Foundation server…

clip_image002

輸入時,必須輸入 http://tfsServer:8080/tfs/CollectionName 如下的測試範例

clip_image004

如果沒有照順序安裝,則上一步輸入 Url 時,Port number 不會變成 disabled 的狀態。

結論

老外對於繁中版好像愈來愈不照顧了。為了之後開發方便,建議大家之後還是使用英文版來開發,比較不會踩地雷。

20140505

Connecting to TFS from any version of Visual Studio 詳細記載了所有的版本連接方式

2010年5月19日 星期三

Window Update KB967723 安裝失敗

這個問題已存在了一段時間了,一直略過不理。
這樣不是辦法。

問題

伺服器是 Windows Server 2008 x86,之前Windows Update 說有新的更新 KB967723,晚上自動更新時卻一直安裝不上去。

手動更新也是失敗。到 這裡 手動下載 patch 檔來更新,也不行。真糟。

今早下定決心,看一下 %Windows%\WindowsUpdate.log,發現了下面的錯誤記錄。

2010-04-02    00:01:09:384    1036    10a0    Report    REPORT EVENT: {DF07C317-A3F9-405F-BF9A-8EDDF5A65E44}    2010-04-02 00:00:38:397+0800    1    195    101    {8181567D-EC57-4B9C-A351-F48324C5D274}    103    80070490    AutomaticUpdates    Failure    Content Install    Installation Failure: Windows failed to install the following update with error 0x80070490: Security Update for Windows Server 2008 (KB967723).

於是再使用 0x80070490 + KB967723 找 Google 大神幫忙。找到了這個解法

什麼是「系統更新整備工具」?

系統資源 (例如檔案資料、登錄資料,甚至是記憶體內部資料) 在作業系統存留期間可能會產生不一致。這些不一致可能是由各種硬體故障或軟體問題所造成的。在某些情況中,這些不一致會影響 Windows 服務存放區,並造成軟體更新無法運作。系統更新整備工具會嘗試解決這些不一致問題。(摘自 http://support.microsoft.com/kb/947821)

完工。

連接 Visual Studio 2005 到 TFS 2010 的詳細步驟 (英文版)

前提到了 舊版 Visual Studio (2005, 2008) 連接到 TFS 2010。其中內容太過簡潔。下面則是 VS2005 完整的安裝步驟,順序不能錯誤,否則無法連接到 TFS2010。

安裝
  1. 安裝 Visual Studio 2005
  2. 安裝 Team Explorer 2005
  3. 安裝 Visual Studio 2005 SP1
  4. 安裝 VSTS 2005 相容 2010 套件

注意!在安步驟3及4時,安裝程式會重複安裝兩次。必須讓安裝程式完整地安裝完畢,否則會無法連接 TFS 2010。

例如在步驟3,雖然只點擊執行一次,但安裝程式會執行兩次,一次更新步驟1的 VS2005 為 VS2005 sp1,第二次則更新步驟2的 Team Explorer 2005 為Team Explorer 2005 sp1。故會安裝兩次。

相同地,步驟4也會安裝兩次,分別更新 VS2005 sp1 及 Team Explorer sp1,讓這兩個產品得以連接 TFS 2010。

我在這個地方等太久了,耐不住性子下就冒然取消,之以就無法連接 TFS 2010 了。害我又錯怪了 MS …

設定

接下來,就可以設定 Team Foundation Server。使用 Tools \  Connect to Team Foundation server…

image

輸入時,必須輸入 http://tfsServer:8080/tfs/CollectionName 如下的測試範例

image

如果沒有照順序安裝,則上一步輸入 Url 時,Port number 不會變成 disabled 的狀態。

另外,要強調的是這裡的網址連結都是英文版的哦!繁體中文版的連結不 work!!!! 驚訝吧!

Build failured 時Create WorkItem 給指定的帳號

問題

當 TFS daily build 失敗時,TFS 預設會自動建立一個 WorkItem (bug) 給執行帳號。這個執行帳號等同於當初建立 TFS 環境的 TFSService 帳號。

問題 TFSService 這個帳號是沒有人在處理的。換句話說,當 bug 指定給 TFSService,沒有人會自動分擔該帳號的 bug。因此建立一個 Team Project 時,就應該指定一個 Build Manager,專案負責該專案建置的問題。

好了,找到了一個人,就稱為 Charles好了。那我們該如何在 TFS 中設定呢?當然我們希望 Build failure 後,直接指定 workitem 給 Charles,而不是給預設的 TFSService。

解法 for TFS 2008

在TFS 2008 時,建置的設定都在 TFSBuild.proj。這個檔案是 xml,因此修改這個 xml 後並 check in 後,就完工了。

首先展開 Team Project ,在 Builds 下找到要修改的 Build definition,按右鍵執行 View Configuration Folder

image

再來修改(並 check out)TFSBuild.proj。找到 WorkItemFieldValues,並加上 Assigned to=Charles; 完成後記得 check in 回 TFS 哦。

<WorkItemFieldValues>System.Reason=Build Failure;System.Description=Start the build using Team Build;Assigned to=Charles;</WorkItemFieldValues>

此後,晚上再有 build failure ,就會指定給 Charles 了。這個Charles 的值,必須參考建立 WorkItem 時 Assigned to 的下拉框的值。

image

解法 for TFS 2010

待完成。到了 TFS 2010 後,TFSBuild.proj 已經改用 Workflow Foundation 來設定了。因此,必須修改 xaml 或使用 WF designer 來設計。

2010年5月18日 星期二

MVC 1.0 專案升級為 2.0

MVC 2.0 已經在 2010/3/12 號出來了。可是我之前寫的 MVC 1.0 的專案該怎麼辦呢?當然是升級。

要升級前,必須確認是否讓 Visual Studio 安裝了 MVC 2.0 的專案樣版。如果是 Visual Studio 2010,就不必安裝了,因為已經內建。如果是 Visual Studio 2008,請到這裡下載。

接下來是升級專案。

  1. 記得先備份方案。
  2. 先將整個方案 Check Out。唯讀屬性會造成升級失敗。Check OUt 後關閉 Visual Studio 2008。
  3. 請到這裡下載轉換器(MvcAppConverter)。
  4. 執行轉換器,並按”Convert”
  5. 再打開 Visual Studio 2008,Build方案。
  6. 完成

是不是很簡單呢?雖然很簡單,但內部作的動作卻很繁複,包含了改參考 MVC2.dll,修改 configuration,修改 csproj等。

參考

2010年5月17日 星期一

連接 Visual Studio 2008 到 TFS 2010 的詳細步驟

之前提到了 舊版 Visual Studio (2005, 2008) 連接到 TFS 2010。其中內容太過簡潔。下面則是 VS2008 完整的安裝步驟,順序不能錯誤,否則無法連接到 TFS2010。

安裝

  1. 安裝 Visual Studio 2008
  2. 安裝 Team Explorer 2008
  3. 安裝 Visual Studio 2008 Service Pack 1
  4. 安裝 VSTS 2008 相容 2010 套件

設定

接下來,就可以設定 Team Foundation Server。使用 Tools \  Connect to Team Foundation server…

image

輸入時,必須輸入 http://tfsServer:8080/tfs/CollectionName 如下的測試範例

image

如果沒有照順序安裝,則上一步輸入 Url 時,Port number 不會變成 disabled 的狀態。

安裝 2010 Build Agent 後,2008 Build 失敗

很高興地完成 TFS2010的安裝後,後續的問題看來不斷地出現。

狀況

這個狀況出現在同一個伺服器當成 TFS 2008 及 TFS 2010 的Build Server 後,TFS 2010 的 Build 就不再成功了。並且有訊息如下

The path C:\Build\…somepath…\Sources is already mapped to workspace BuildServer_23.

問題

TFS2008在workspace命名上,必須相關於machine name 及 build definition。故名稱常常為 BuildServer_18 這樣的名字。而 TFS2010則需再加上 Build Agent的名稱,因為在 TFS 2010 之後,可以在同一台machine 上擁有多個 Build Agent.

在 TFS 2008 及 TFS 2010 有些衝突的情形下,該已存在的 workspace 必須先自行手動刪除後,再讓 TFS2008 及 TFS 2010 重新建立即可。

解決

在 build machine 上執行下面的指令

步驟一

查詢到底有哪些 workspaces

tf workspaces
更進一步的,需要指定 collectionUrl
tf workspaces /collection:http:/tfsserver:8080/tfs/defaultcollection /owner:*

 

步驟二

刪除衝突的 workspace

tf workspace /delete buildMachine_18;ownerName /server:tfsServerName
舉例來說:
tf workspace /delete workspaceName;tfsservice /server:http://tfsserver:8080/tfs/defultcollection

參考

2010年5月16日 星期日

MVC 的快速鍵

在開發程式的過程中,最好不要經常使用滑鼠。想想一下,打不到幾個字就要挪一下滑鼠,再打幾個字,是非常沒效率的事。

MVC 的開發中,最常見的是 Add Controller, Add View,或者在 Controller 與 View之間切換。快速鍵如下

Action ShortCut Key
Add Controller Ctrl + M, Ctrl + C
Add View Ctrl + M, Ctrl + V
Controller, View 的切換 Ctrl + M, Ctrl + G

2010年5月14日 星期五

MVC 2.0 的建置與 TFS 2010

雖然與過往的 WebForm 差異甚大,但在使用 MVC 2.0 來建立網站仍是一個美好的經驗。

更佳者,是內建了 MvcBuildViews 的功能。

MvcBuildViews

以往在建置Asp.net WebForm 網站時,Web Application 的編譯並不包含 aspx的部份。換句話說,WebApplication可在 Visual Studio 編譯成功,但在 aspx 上的語法如果有錯誤的話,只有該網頁在執行時期才會發現錯誤。

asp.net 有個 PreCompile 的機制,可以提早發現這類的錯誤。但並沒有整合到開發環境中,總是要等到上線時才被客戶踩到地雷後,才怪微軟怎麼 compile 會過。

因此,在 asp.net MVC 中,增加了 MvcBuildViews 的機制。也就是在編譯時期提早編譯 View 的部份。

這個選項預設是 false。必須以 xml 的方式打開 .csproj,找到 MvcBuildViews,將其值改為 true,才會編譯 View。

<Project ...> 
  ... 
  <MvcBuildViews>true</MvcBuildViews> 

其實這裡的作業方式仍然是作 asp.net 的 precompile。見 .csproj 最下方有個 build target,引導 MSBuild 在 Compile 完畢後接著再執行 aspnet_compile。

<Target Name="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
  <AspNetCompiler VirtualPath="temp" PhysicalPath="$(ProjectDir)" />
</Target>

TFS 2010

導入 TFS 2010後,上述的 MvcBuildViews 的選項會導致 Build Machine 編譯失敗。失敗的錯誤訊息如下

/temp/global.asax (1): Could not load type 'XXX.MvcApplication'.

原因呢?我認為MVC 的MvcBuildViews的設計僅就開發人員在 Desktop 上能進行編譯即可,故把 Project 的路徑等同於Build的路徑。而TFS在編譯時,並非將專案的路徑當成編譯的輸出路徑,故$(ProjectDir) 的值並非完整編譯後的可執行環境。

因此,我們必須針對該 .csproj 進行修改。修改 csproj 時必須顧慮到開發人員及 TFS 的 Build machine 同時可以編譯的需求,我作了下面的改變。

<Target Name="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
  <AspNetCompiler VirtualPath="temp" PhysicalPath="$(WebProjectOutputDir)" />
</Target>
也就是改變 $(ProjectDir) 為 $(WebProjectOutputDir)。

MVCContrib

在使用了 MVCContrib 的元件後,上述的 Team Build 又失敗了。錯誤訊息如下

c:\Builds\1\…\PublishedWebsites\xxx\Web.config (114): The type or namespace name 'MvcContrib' could not be found (are you missing a using directive or an assembly reference?)

我在MVC 網站所參考的 MVCContrib.dll 竟不見了。不知為何?原來,我忘了將MVCContrib.dll加入Source Control 中了。到了 Build Server 找不到該dll.

參考

舊版 Visual Studio (2005, 2008) 連接到 TFS 2010

在 Visual Studio 2010 中,Team Explorer 已經是內建的了。換句話來說, Visual Studio 2001 不必安裝其他元件,就可以連接到 TFS 2010。

然而,舊版的 Visual Studio,如  2005 及 2008 要使用 TFS 2010,該怎麼辦呢?

簡單地說,就是安裝新的軟體,以支援連接到 TFS 2010.

VSTS 2008 相容 2010 套件 ( 請升到 SP1 )

http://www.microsoft.com/downloads/details.aspx?displaylang=zh-tw&FamilyID=cf13ea45-d17b-4edc-8e6c-6c5b208ec54d

VSTS 2005 相容 2010 套件 ( 請升到 SP1 )

http://www.microsoft.com/downloads/details.aspx?displaylang=zh-tw&FamilyID=22215e4c-af6f-4e2f-96df-20e94d762689

後記1

[20100518]雖然微軟出了這兩個套件,但我只試成功了 Visual Studio 2008的部份,見連接 Visual Studio 2008 到 TFS 2010 的詳細步驟。Visual Studio 2005 想要比照辦理,卻試不出來。不知道微軟是不是有測過呢?

後記2

[20100519]試出來了,過程見 連接 Visual Studio 2005 到 TFS 2010 的詳細步驟。我又錯怪了微軟。

回擲例外 Rethrow caught exceptions

當處理例外時,如需回擲同一例外時,應該處理正確。

錯誤範例:

catch( Exception ex )
{
ExceptionPolicy.Handle( ex, “Crital” );
throw ex;   //不正確。這樣會遺失掉例外的StackTrace
}

使用 throw ex 時,會使用新的 call stack,故例外被上一層補獲時,記錄的 StackTrace 不是原本的例外的StackTrace。

正確範例:

catch( Exception ex )
{
ExceptionPolicy.Handle( ex, “Crital” );
throw;   //正確。
}

使用 throw 時,會使用原有例外的的 call stack,故例外被上一層補獲時,記錄的 StackTrace就是我們想要的。

2010年5月12日 星期三

如何使用 In 的查詢語法,而且防止 Sql Injection

有同事問到,如果需要以 in 的 sql 語法查詢時,要如何防止Sql Injection?

問題需要一步步的解決。首先寫個範例,是查詢在 AdventureWorks 的資料表是否有指定的資料表名稱。程式如下。

範例一

   1: class Program
   2:   {
   3:     static void Main(string[] args)
   4:     {
   5:       Database db = DatabaseFactory.CreateDatabase();
   6:  
   7:       string query = "select name, object_id from sys.tables where name in ('Store','ProductPhoto','ProductProductPhoto','StoreContact')";
   8:       var tables = db.ExecuteSqlStringAccessor<Table>(query);
   9:       foreach (var table in tables)
  10:         Console.WriteLine("{0}:{1}", table.Object_Id, table.Name);
  11:     }
  12:   }
  13:  
  14:   class Table
  15:   {
  16:     public int Object_Id { get; set; }
  17:     public string Name { get; set; }
  18:   }

範例一中使用了 Enterprise Library 5 中的 DAAB 來讀取資料,並將符合條件的資料表的 name , object_id 列表出來。

現在呢?需要將查詢的資料表名稱參數化,作成一個 Method,方便 UI 呼叫。

範例二

   1: static void Main(string[] args)
   2:     {
   3:  
   4:       string tableNames = "'Store','ProductPhoto','ProductProductPhoto','StoreContact'";
   5:       var tables = GetTables(tableNames);
   6:       foreach (var table in tables)
   7:         Console.WriteLine("{0}:{1}", table.Object_Id, table.Name);
   8:     }
   9:  
  10:     private static IEnumerable<Table> GetTables(string strTableNames)
  11:     {
  12:       Database db = DatabaseFactory.CreateDatabase();
  13:       
  14:       string query = "select name, object_id from sys.tables where name in (" + strTableNames + ")";
  15:       var tables = db.ExecuteSqlStringAccessor<Table>(query);
  16:       return tables;
  17:     }
  18:  
  19:     class Table
  20:     {
  21:       public int Object_Id { get; set; }
  22:       public string Name { get; set; }
  23:     }

要查詢的資料表名稱以符合 sql 語法查詢的方式GetTables 方法。GetTables 的實作中,直接以組字串的方式組成了 sql script。這樣寫,執行起來並沒有錯誤。卻是標準的Sql Injection 入侵範例。尤其是呼叫 GetTables 的 Layer 是網頁時,就更需要擔心了。

我們改成寫下面的範例三。

範例三

   1: class Program
   2:   {
   3:     static void Main(string[] args)
   4:     {
   5:       string[] tableNames = { "Store","ProductPhoto","ProductProductPhoto","StoreContact"};
   6:       var tables = GetTables(tableNames);
   7:       foreach (var table in tables)
   8:         Console.WriteLine("{0}:{1}", table.Object_Id, table.Name);
   9:     }
  10:  
  11:     private static IEnumerable<Table> GetTables(string[] tableNames)
  12:     {
  13:       Database db = DatabaseFactory.CreateDatabase();
  14:       
  15:       List<string> tableName = (from t in tableNames
  16:                                select string.Format("'{0}'", t)).ToList();
  17:       string strTableNames = string.Join(",", tableName.ToArray());
  18:       string query = "select name, object_id from sys.tables where name in (" + strTableNames + ")";
  19:       var tables = db.ExecuteSqlStringAccessor<Table>(query);
  20:       return tables;
  21:     }
  22:   }
  23:  
  24:   class Table
  25:   {
  26:     public int Object_Id { get; set; }
  27:     public string Name { get; set; }
  28:   }

要查詢的資料表名稱以陣列的方式傳入 GetTables 方法。GetTables 的實作中,仍然以組字串的方式組成了 'Store,ProductPhoto,ProductProductPhoto,StoreContact' 的字串,再以 in 的sql 查詢語法來下 sql script.

這樣寫,執行起來並沒有錯誤。Sql Injection 的可能性也不高,因為 tableNames 的字串陣列需要被重組。

但,仍是是組字串的方式來組合  sql script,容易被當成 sql injection 的攻擊漏洞,CAT.NET 還是會檢查出來的。

範例四

   1: class Program
   2:   {
   3:     static void Main(string[] args)
   4:     {
   5:       string[] tableNames = { "Store", "ProductPhoto", "ProductProductPhoto", "StoreContact" };
   6:       var tables = GetTables(tableNames);
   7:       foreach (var table in tables)
   8:         Console.WriteLine("{0}:{1}", table.Object_Id, table.Name);
   9:     }
  10:  
  11:     private static IEnumerable<Table> GetTables(string[] tableNames)
  12:     {
  13:       Database db = DatabaseFactory.CreateDatabase();
  14:  
  15:       string strTableNames = string.Join(",", tableNames.ToArray());
  16:       string query = "select name, object_id from sys.tables where name in ( select value from dbo.fn_split(@strTableNames, ','))";
  17:  
  18:       IRowMapper<Table> rowMapper = MapBuilder<Table>.BuildAllProperties();
  19:       var accessor = new SqlStringAccessor<Table>(db, query, new MyParameterMapper(), rowMapper);
  20:       var tables = accessor.Execute(strTableNames);
  21:       return tables;
  22:     }
  23:  
  24:   }
  25:  
  26:   class Table
  27:   {
  28:     public int Object_Id { get; set; }
  29:     public string Name { get; set; }
  30:   }
  31:  
  32:   public class MyParameterMapper : IParameterMapper
  33:   {
  34:     public void AssignParameters(DbCommand command, object[] parameterValues)
  35:     {
  36:       DbParameter parameter = command.CreateParameter();
  37:       parameter.ParameterName = "@strTableNames";
  38:       parameter.Value = parameterValues[0];
  39:       command.Parameters.Add(parameter);
  40:     }
  41:   }

而 dbo.fn_split 列在下面

   1: if exists (select * from dbo.sysobjects where id = OBJECT_ID(N'[dbo].[fn_Split]') and xtype in (N'FN', N'IF', N'TF'))
   2: drop function [dbo].[fn_Split]
   3: GO
   4:  
   5: SET QUOTED_IDENTIFIER OFF 
   6: GO
   7:  
   8: SET ANSI_NULLS OFF 
   9: GO
  10:  
  11: CREATE  FUNCTION fn_Split(@text varchar(8000), @delimiter varchar(20) = ' ')
  12: RETURNS @Strings TABLE
  13: (    
  14:   position int IDENTITY PRIMARY KEY,
  15:   value varchar(8000)   
  16: )
  17: AS
  18: BEGIN
  19: DECLARE @index int 
  20: SET @index = -1 
  21:  
  22: WHILE (LEN(@text) > 0) 
  23:   BEGIN  
  24:     SET @index = CHARINDEX(@delimiter , @text)  
  25:     IF (@index = 0) AND (LEN(@text) > 0)  
  26:       BEGIN   
  27:         INSERT INTO @Strings VALUES (@text)
  28:           BREAK  
  29:       END  
  30:  
  31:     IF (@index > 1)  
  32:       BEGIN   
  33:         INSERT INTO @Strings VALUES (LEFT(@text, @index - 1))   
  34:         SET @text = RIGHT(@text, (LEN(@text) - @index))  
  35:       END  
  36:     ELSE 
  37:       SET @text = RIGHT(@text, (LEN(@text) - @index)) 
  38:     END
  39:   RETURN
  40: END
  41: GO
  42:  
  43: SET QUOTED_IDENTIFIER OFF 
  44: GO
  45:  
  46: SET ANSI_NULLS ON 
  47: GO

這樣的方法就相當長了。但卻也相當好用。尤其是 fn_split 可用來拆解字串成為新的 table 並在 sql 中使用。

SqlStringAccessor 是 Enterprise Library 5 中 DAAB 的新成員,目的是建立出新的 DTO。

Share with Facebook