2016年7月20日 星期三

ORA-12154: TNS: 無法解析指定的連線 ID

在本機建立好連接 oracle 的表單,放入 IIS7 上執行時,竟然發生

ORA-12154: TNS: 無法解析指定的連線 ID

檢查了 TNS 和 Oracle 版本,都和本機的相同,TNS 的設定跟其的 Oralce DB 就差了 sid 的屬性,但不明白為何本機可以但 Server 上不行

後來把 connectstring 改為放入完整的 tns,竟然可以了

參考來源:
http://stackoverflow.com/questions/12571379/oracleconnection-open-is-throwing-ora-12541-tns-no-listener

主版頁面的圖片顯示路徑

今天第一次把 VS 2015 的 asp.net 網站專案放上測試區 Windows 2003 Server / IIS 7上面,結果發生了一些以前沒遇過的事情

1. 發佈時網站預設是沒有預先編譯的,要記得打勾
2. 在主版頁面有放圖片用 <img src = "~/img/....jpg" /> ,但是實際運作時看不到圖片,看了圖片的原始位置,發現圖片的網址怪怪...,又不想依各頁面來分別把路徑寫死,google 了一下找到了這一篇

http://stackoverflow.com/questions/5190769/html-img-and-asp-net-image-and-relative-paths

只要在 <img /> 內加入 runat="server " 即可
 <img src="~/App_Themes/Default/images/two.gif" runat="server" />

2016年7月6日 星期三

Visual Studio 2013 會有 JavaScript 執行階段錯誤: Syntax error...

因為要用到在  ASPXGridView 的 Batch Clone 功能,而把 Developer Express 升級到 15.2 之後,發現會出現以下的錯誤,

未處理的例外狀況 位於行 37,欄 59140 在 http://localhost:60666/dc15f9e0341a4844924fd80f41006451/browserLink 中

0x800a139e - JavaScript 執行階段錯誤: Syntax error, unrecognized expression: a#gridView_DXCBtn%DXItemIndex0%



耗了 2 天在 debug javascript 後發現問題原因不是嫩嫩我能夠解的,就算關閉了例外警告還是會出錯,後來就專心 google 這個問題

在 https://www.devexpress.com/Support/Center/Question/Details/Q571501 ,有看到類似的問題有得到了解答,詳細原因其實我看不太懂,只知道在 https://blogs.msdn.microsoft.com/webdev/2013/06/28/browser-link-feature-in-visual-studio-preview-2013/ 說的,在 web.config <appSettings> 中加入下列就可以解決

  <appSettings>
    <add key="vs:EnableBrowserLink" value="false"></add>
  </appSettings>

試了一下,果然再也不會彈出 Syntax error 了.....

2014年7月10日 星期四

使用 DirectoryInfo().Getfiles("*.xls") 會將 *.xlsx 列出來 ???


今天有朋友問我一個問題,使用 DirectoryInfo().Getfiles("*.xls") ,該目錄中若有檔案為 *.xlsx ,則連 *.xlsx 都會一起 list 出來

寫法如下,一般都是這樣子寫,看起來沒什麼異狀...
DirectoryInfo di = new DirectoryInfo(@"d:\temp");
            FileInfo[] files = di.GetFiles("*.xls");
            foreach (FileInfo fi in files)
            {
                string sfullname =  fi.FullName;
            }

後來改為以下的寫法,用 Where 下檔名的條件就可以解決了...

List<string> sfiles = Directory.GetFiles(@"d:\temp", "*.*").Where(file => file.ToLower().EndsWith("xls")).ToList();
            foreach (string file in sfiles)
            {
                FileInfo fi = new FileInfo(file);
                //(.....)
            }

舉一反三,若要取得二個以上的副檔名檔案列表呢? Where 條件中加個 || (OR) 條件就好了

List<string> sfiles = Directory.GetFiles(@"d:\temp", "*.*").Where(file => file.ToLower().EndsWith("xls")  || file.ToLower().EndsWith("html") ).ToList();


2014年5月17日 星期六

庫存不足,不允許過帳還原


在出貨單按下扣帳還原,若是網路或是Tiptop 有問題,有很大的機率會出現已扣帳還原,但庫存還未加回,造成庫存錯誤,此時若再庫存重算也仍無法解決問題
手動處理的方式是找到該料號的 icd21,把數量清除即可。





2014年5月2日 星期五

IIS7 + dotNetFramework 4.5.1 不能運行


IIS7 + dotNetFramework 4.5.1 不能運行

執行了 v4.xxx.xxx aspnet_regiis -i 仍不能運行,後來再重啟 IIS  及應用程式集區之後就可以執行了,在 Server 顯示正常,但從本機瀏覽網頁卻變成 下圖,格式都跑掉了



修改加入了以下這行後顯示就正常了
<system.webServer>
    <modules runAllManagedModulesForAllRequests="true" >
      <remove name="FormsAuthenticationModule" />
    </modules>
  </system.webServer>



2014年4月29日 星期二

[EFGP] FormScript with jQuery

今天在測試 EasyFlow GP 透過 jQuery 使用 C# 寫的 Webservice

在 VisualStudio 中用 c# 寫的程式可以正常呼叫,但是透過 EFGP 就不能
試了半天之後終於得到答案了,在這裡做個筆記

1. jQuery.noConflict(); //避免 $ 與其他 jQuery UI 的衝突 ,在這個範例上沒有設也ok
2. jQuery.support.cors = true; // 跨網域要把它設為 true , 就是這一點搞了非常久

範例如下:

FormScript :

document.write('<script type="text/javascript" src="../../js/jquery-1.7.1.min.js"></script>');

 
function GetInfo() {
  //jQuery.noConflict(); 
  jQuery.support.cors = true;
  //var jq = jQuery.noConflict();
       var $res;
       $.ajax({
           type: "POST",
           url: "http://10.1.10.103:8888/JsonServiceSample.asmx/GetOneUserInfo",
           contentType: "application/json; charset=utf-8",
           async: false,
           cache: false,
          dataType: 'json',
          data: "{name:'Test',age:29}",
          success: function (data) {
              if (data.hasOwnProperty("d")) {
                  $res = data.d;
              }
              else
                  $res = data;
          },
          error: function (xhr, ajaxOptions, thrownError) {
         alert('WS status = ' + xhr.status );
         alert('WS Error =' + thrownError);
        }
      });
      return $res;
  }


function btnEdit_onclick() {
    var res = GetInfo();

    alert(res.Name);
    alert(res.Age);
}



WebService




using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Script.Services;
using System.Web.Services;
using System.Web.Services.Protocols;    //加上這個預備給 Java Call

namespace JQueryWebService
{

    public class User
    {
        public string Name { get; set; }

        public int Age { get; set; }

    }

    /// <summary>
    /// 移除 NameSpace
    /// 每一個 Methods 上面必須加上 
    /// [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
    /// </summary>
    [WebService(Namespace = "", Description = "For Donma Test")]
    [System.ComponentModel.ToolboxItem(false)]
    [ScriptService]
    public class JsonServiceSample : System.Web.Services.WebService
    {
        [WebMethod]
        [SoapRpcMethod(Use = System.Web.Services.Description.SoapBindingUse.Literal)] 
        [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
        public string GetUserInfoString(string name, int age)
        {
            return name + "," + age;
        }

        [WebMethod]
        [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
        public User GetOneUserInfo(string name, int age)
        {
            return (new User { Name = name, Age = age });
        }


        [WebMethod]
        [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
        public User[] GetUsers(string name, int age)
        {
            List<User> res = new List<User>();
            res.Add(new User { Name = name + "1", Age = age });
            res.Add(new User { Name = name + "2", Age = age });

            return res.ToArray();
        }
    }
}

2014年2月9日 星期日

第一個可能發生的例外狀況類型 'System.Threading.ThreadAbortException' 發生於 mscorlib.dll


從  VS2010 到 VS2013後,原來的程式碼發生了一個錯誤訊息:

Server.Transfer("url", true);

第一個可能發生的例外狀況類型 'System.Threading.ThreadAbortException' 發生於 mscorlib.dll

其他資訊: 執行緒已經中止。

要改成為
Response.Redirect("url",false);

這樣子就沒問題了。



2014年1月6日 星期一

T-SQL 日期格式轉換成文字

每次到了要轉換日期格式的時候都會特別想念 Oracle ,只要下 to_char(date, format) 指令就可以輕鬆完成日期轉成文字
但沒辦法,手上的專案就是使用 SQL Server ,該來的還是躲不掉,只是每次都會忘,忘了就要查 Google ,

Will 大的這一篇寫得非常完整,就拿來引用
http://blog.miniasp.com/post/2008/02/27/Use-CONVERT-function-to-deal-with-SQL-Server-Datetime.aspx

摘錄其範例如下:
輸出格式:2008-02-27 00:25:13
SELECT CONVERT(char(19), getdate(), 120)

輸出格式:2008-02-27
SELECT CONVERT(char(10), getdate(), 20)

輸出格式:2008.02.27
SELECT CONVERT(char(10), getdate(), 102)

輸出格式:08.02.27
SELECT CONVERT(char(8), getdate(), 2)

輸出格式:2008/02/27
SELECT CONVERT(char(10), getdate(), 111)

輸出格式:08/02/27
SELECT CONVERT(char(8), getdate(), 11)

輸出格式:20080227
SELECT CONVERT(char(8), getdate(), 112)

輸出格式:080227
SELECT CONVERT(char(6), getdate(), 12)


以下摘錄 MSDN 的樣式說明
http://msdn.microsoft.com/zh-tw/library/ms187928.aspx


日期和時間樣式

當 expression 是日期或時間資料類型時, style 就可以是下表所列的其中一個值。 其他值則當做 0 處理。 從 SQL Server 2012 開始,當從日期和時間類型轉換為datetimeoffset 時,唯一支援的樣式為 0 或 1。 所有其他轉換樣式都會傳回錯誤 9809。
SQL Server 利用科威特演算法來支援阿拉伯文樣式的日期格式。
不含世紀 (yy) (1)
含世紀 (yyyy)
標準
輸入/輸出 (3)
-
0 或 100 (1,2)
預設
mon dd yyyy hh:miAM (或 PM)
1
101
美式英文
1 = mm/dd/yy
101 = mm/dd/yyyy
2
102
ANSI
2 = yy.mm.dd
102 = yyyy.mm.dd
3
103
英式英文/法文
3 = dd/mm/yy
103 = dd/mm/yyyy
4
104
德文
4 = dd.mm.yy
104 = dd.mm.yyyy
5
105
義大利文
5 = dd-mm-yy
105 = dd-mm-yyyy
6
106 (1)
-
6 = dd mon yy
106 = dd mon yyyy
7
107 (1)
-
7 = Mon dd, yy
107 = Mon dd, yyyy
8
108
-
hh:mi:ss
-
9 或 109 (1,2)
預設值 + 毫秒
mon dd yyyy hh:mi:ss:mmmAM (或 PM)
10
110
美國
10 = mm-dd-yy
110 = mm-dd-yyyy
11
111
日本
11 = yy/mm/dd
111 = yyyy/mm/dd
12
112
ISO
12 = yymmdd
112 = yyyymmdd
-
13 或 113(1、2)
歐洲預設值 + 毫秒
dd mon yyyy hh:mi:ss:mmm(24h)
14
114
-
hh:mi:ss:mmm(24h)
-
20 或 120 (2)
ODBC 標準
yyyy-mm-dd hh:mi:ss(24h)
-
21 或 121 (2)
ODBC 標準 (含毫秒)
yyyy-mm-dd hh:mi:ss.mmm(24h)
-
126 (4)
ISO8601
yyyy-mm-ddThh:mi:ss.mmm (無空格)
附註 附註
如果毫秒 (mmm) 的值為 0,將不會顯示毫秒值。 例如,'2012-11-07T18:26:20.000' 值會顯示為 '2012-11-07T18:26:20'。
-
127(6, 7)
具有時區 Z 的 ISO8601。
yyyy-mm-ddThh:mi:ss.mmmZ (無空格)
附註 附註
如果毫秒 (mmm) 的值為 0,將不會顯示毫秒值。 例如,'2012-11-07T18:26:20.000' 值會顯示為 '2012-11-07T18:26:20'。
-
130 (1,2)
回曆 (5)
dd mon yyyy hh:mi:ss:mmmAM
在此樣式中,mon 代表完整月份名稱的多 Token 回曆 unicode 表示法。 這個值無法在預設 SSMS 美國安裝中正確呈現。
-
131 (2)
回曆 (5)
dd/mm/yyyy hh:mi:ss:mmmAM
1 這些樣式值會傳回不具決定性的結果。 其中包括所有 (yy) (不含世紀) 樣式和 (yyyy) (含世紀) 樣式的子集。
2 預設值 (style0 或 100、9 或 109、13 或 113、20 或 120 及 21 或 121) 一律會傳回世紀 (yyyy)。
3 當轉換成 datetime 時輸入;當轉換成字元資料時輸出。
4 專為了 XML 而設計。 如果是從 datetime 或 smalldatetime 轉換成字元資料,輸出格式會符合上表的描述。
5 回曆是有多種變化的日曆系統 SQL Server 使用科威特演算法。
重要事項 重要事項
根據預設,SQL Server 會根據截止年份 2049 來解譯兩位數的年份。 也就是說,兩位數年份 49 會解譯為 2049,而兩位數年份 50 會解譯成 1950。 許多用戶端應用程式 (例如根據 Automation 物件的應用程式) 都使用截止年份 2030 年。 SQL Server 提供的 two digit year cutoff 組態選項會變更 SQL Server 所使用的截止年份,並允許以一致方式處理日期。 我們建議您指定四位數的年份。
6 只有在從字元資料轉換為 datetime 或 smalldatetime 時才支援。 當只代表日期或只代表時間元件的字元資料轉換為 datetime 或 smalldatetime 資料類型時,未指定的時間元件會設定為 00:00:00.000,而未指定的日期元件則會設定為 1900-01-01。
7 選擇性的時區指標 Z 可用來輕鬆地將具有時區資訊的 XML datetime 值對應到沒有時區的 SQL Server datetime 值。 Z 是時區 UTC - 0 的指標。 其他的時區是以 + 或 - 方向位移的 HH:MM 來代表。 例如:2006-12-12T23:45:12-08:00。
當您從 smalldatetime 轉換成字元資料時,包括秒或毫秒的樣式會在這些位置顯示零。 當您從 datetime 或 smalldatetime 值轉換時,您可以利用適當的 char 或 varchar資料類型長度來截斷不需要的日期部分。
當您從含有時間之樣式的字元資料轉換成 datetimeoffset 時,時區時差就會附加至結果。

2013年12月23日 星期一

ASP.NET IE10,IE11 要在相容性檢視下才正常

ASP.NET IE10,IE11 要在相容性檢視下才正常
這個問題已經困擾許久,一直找不出解決方式,尤其是最近 User 的瀏覽器陸續升級到 IE 11 ,短期的解決方式是將網域加入相容性檢視清單,但畢竟這不是永久解決的方式

更新 Developer Express 13.2 ,但仍無法解決問題

但後來找到了
http://blogabhijeet.blogspot.in/2013/10/ie11-and-windows-81-solution-for.html
他有一些建議的解決方式

其中這一項是 MS 的 Hot fix
http://www.microsoft.com/zh-tw/download/confirmation.aspx?id=39257
我們是 Windows 7 , Windows 2008Server 64bit  ,故下載 64 bit 的版本
NDP40-KB2836939-v3-x64.exe

重啟  IIS 後終於解決了長久以來的問題了

2013年12月10日 星期二

Toptop 顯示目前線上人數


/* 顯示目前線上人數 */
/* 可以在 Linux 下 kill -9 PID ,就可以趕它出去 */
select * from gbq_file
order by GBQ03

/* 顯示1天前登入的人員列表 */
select * from gbq_file
where to_date(gbq07,'yy/MM/dd hh24:mi:ss') < sysdate -1
order by GBQ03

2013年1月30日 星期三

OpenLdap Authorization


最近要做 OpenLdap 的 Authorization , 但是一直 try  不成功,直到看到以下的回覆,真的是幫助很大

http://www.cnblogs.com/wangyt223/archive/2012/10/09/2716077.html


(转)DirectoryServices访问OpenLdap的若干问题

DirectoryServices访问OpenLdap的若干问题 (入选推荐日志,加10币)
      昨天晚上快2点才睡,终于把使用DirectoryServices访问OpenLdap的所有问题都解决了,这方面的资料好像国内的不多,遇到很多问题都是自己摸索,或者在国外的论坛上看到的。
       1.DirectoryEntry的AuthenticationTypes必须设置成ServerBind
       2.ldap直接认证,可以使用DirectoryEntry.NativeObject,只要不返回错误,就可以认为认证成功
       3.搜索可以使用DirectorySearcher,调用 mySearchResult.GetDirectoryEntry可以对搜索项进行修改
       4.Attribute Types 为Octet String 的必须string和asc byte数组类型之间转换(该类型一般用在password上)
       5.新加用户使用DirectoryEntry.Children.Add的方法,该方面有两个参数,一个是dn,另一个为加入的Schema 的objectclass(注意千万不要忘记了所有在Schema中定义的必填项,否则会返回LDAP_NAMING_VIOLATION的错误)
       6.当然,任何修改都需要.CommitChanges()
       另外还有个遗留的小问题,Adsi Edit无法访问  OpenLdap,不知道是不是设置有问题

把 code 放上來,以供日後參考
public static string ValidateUser(string ComputerName, string UserName, string Password)
        {
            string strPath;
 
            if (ComputerName.IndexOf('.') != -1)
            {
                strPath = string.Format("LDAP://{0}:389/DC=alchip,DC=com",ComputerName);
                UserName = string.Format("uid={0},ou=Users,DC=alchip,DC=com",UserName);
            }
            else
            {
                strPath = string.Format(@"WinNT://{0}/{1}, user", ComputerName, UserName);
            }
 
            DirectoryEntry entry = new DirectoryEntry(strPath, UserName, Password,AuthenticationTypes.ServerBind);
          
            
            try
            {
                //string objectSid =
                //      (new SecurityIdentifier((byte[])entry.Properties["objectSid"].Value, 0).Value);
 
                //return objectSid;
 
                if (entry.NativeObject != null)
                    return "true";
                else
                    return null;
            }
            catch// (DirectoryServicesCOMException)
            {
                return null;
            }
            finally
            {
                entry.Dispose();
            }
        }

Crystal Report 加總功能失效


有一支報表的表尾加總出現了問題,總是只有出現第一筆數量,而非加總的數量

1. 在群組欄位中按右鍵->插入->摘要,則可以在報表尾產生一個加總的資料
2. 或在報表尾按右鍵加入欄位


但是不知道是不是這樣子就可以一勞永逸 ? 於就是檢梘了加總的欄位設定
有一些許的差異,改掉之後報表的加總欄位就又可以運作了...



2012年10月23日 星期二

連接 Oracle 不依靠 tnsname.ora


有朋友問了一個問題, VB 只能用 tnsname.ora 內的 tns 來連線,而不能動態連,想連哪裡就連哪裡嗎?


解答在這裡:
http://www.devx.com/tips/Tip/27775




    Dim TNS_INFO As String
    Dim cnxDB As New ADODB.Connection
 
    TNS_INFO = "(DESCRIPTION=" & _
                       "(ADDRESS_LIST=" & _
                       "(ADDRESS=(PROTOCOL=TCP)" & _
                       "(HOST=資料庫位址)" & _
                       "(PORT=埠號)))" & _
                       "(CONNECT_DATA=(SID=SID名稱)" & _
                       "(SERVER=DEDICATED)))"
                     
   若是沒有 OraOLEDB.Oracle 的話,用 MSDAORA.1 也是可以的

    'cnxDB.ConnectionString = "Provider=MSDAORA.1;" & _

    cnxDB.ConnectionString = "Provider=OraOLEDB.Oracle;" & _
                       "Data Source=" & TNS_INFO & ";" & _
                       "user id=帳號;" & _
                       "password=密碼"
    Debug.Print cnxDB.ConnectionString

2012年10月18日 星期四

月結時發現工單數錯誤,多開數量 --> 工單退料




若是工單多開數量,但是工單已發料並且再製了,此時倒單會有很重的 loading,故要執行
asfi526/asfi526_icd 來新增退料單,其中的資訊都和工單相同,如此一來在月結時資料才正確

******
列出一個SQL script 來查詢未結工單的列表,以後有時間再寫成 p_query 或網頁來查詢
******

  SELECT *
    FROM (  SELECT DISTINCT sfb01, --工單號碼
                            sfb081, --發料量
                            SFB09, --完工量
                            SFB12, --報廢量
                            SFB05, --料號
                            SFB91, --採購單號
                            SFB81,  --工單日期
                            sfb04,  --結案狀態 7-未結案
                            (sfb081 - sfb09 - sfb12) unclosedqty, --未結數量
                            MAX (rva06) m_rva06 --最後發料日期
              FROM alchip_tw.sfb_file a,
                   alchip_tw.rvb_file b,
                   alchip_tw.rva_file c
             WHERE     sfb81 >= TO_DATE ('2012/08/01', 'yyyy/mm/dd')
                   AND sfb81 <= TO_DATE ('2012/08/31', 'yyyy/mm/dd')
                   AND sfb04 = 7 --代表未結案狀態
                   AND rvb01 = rva01
                   AND rvb34 = sfb01
                   AND rvaconf = 'Y'
          GROUP BY sfb01,
                   sfb081,
                   SFB09,
                   SFB12,
                   SFB05,
                   SFB91,
                   SFB81,
                   sfb04
          ORDER BY sfb01)
   WHERE m_rva06 < TO_DATE ('2012/09/01', 'yyyy/mm/dd')
ORDER BY unclosedqty


2012年9月20日 星期四

庫存資料手動調整

庫存的資料基本上是不能手動去資料庫調整,但若是遇到大量資料匯入錯誤,要倒單要改庫存會很不容易,若該料在的同一張單內有 100筆資料,但如果有一筆有問題,亦要將其他的資料也倒回去才可以進系統修改

故與顧問討論後,可以在資料庫修改庫存,但修改完後必須做庫存重算的動作

庫存重算,原則上是結完帳後才要做,但手動改庫存會有不可預知的情形,可能相關的料件存會有問題,所以還是要重算 (有動到庫存則要從該月份庫存重計)
步驟:
1. aimp610

2. aimp620
要逐月來操作,aimp610 (2012/7) -> aimp620(2012/7) -> aimp610 (2012/8) -> aimp620(2012/8)  ....


要手動調整資料,相關的 Table 有:

inb_file, idc_file,idd_file,img_file,ima_file,imk_file,imgg_file,tlf_file,tlff_file

數量:


inb_fileàinb907、imgg_fileàimgg10、tlff_fileàtlff10


**切記,調完資料後要做庫存重算,再去庫存資料來看庫存有沒有問題**

2012年9月14日 星期五

EnterPrise Library DAAB 用法


留存備查!!

//===============================================================================
// Microsoft patterns & practices Enterprise Library
// Data Access Application Block Examples
//===============================================================================
// Copyright © Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
 
using System;
using System.ComponentModel;
using System.Linq;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Threading;
using System.Xml;
using System.Transactions;
 
using DevGuideExample.MenuSystem;
 
// references to configuration namespaces (required in all examples)
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
 
// references to application block namespace(s) for these examples
using Microsoft.Practices.EnterpriseLibrary.Data;
using Microsoft.Practices.EnterpriseLibrary.Data.Sql;
 
namespace DataAccessExample
{
    class Program
    {
        static Database defaultDB = null;
        static Database namedDB = null;
        static SqlDatabase sqlServerDB = null;
        static Database asyncDB = null;
 
        static void Main(string[] args)
        {
            #region Resolve the required objects
 
            // Resolve the default Database object from the container.
            // The actual concrete type is determined by the configuration settings.
            defaultDB = EnterpriseLibraryContainer.Current.GetInstance<Database>();
 
            // Resolve a Database object from the container using the connection string name.
            namedDB = EnterpriseLibraryContainer.Current.GetInstance<Database>("ExampleDatabase");
 
            // Resolve a SqlDatabase object from the container using the default database.
            sqlServerDB = EnterpriseLibraryContainer.Current.GetInstance<Database>() as SqlDatabase;
 
            // Resolve a SqlDatabase object that has "Asynchronous Processing=true" in the connection string.
            asyncDB = EnterpriseLibraryContainer.Current.GetInstance<Database>("AsyncExampleDatabase");
 
            #endregion
 
            new MenuDrivenApplication("Data Access Block Developer's Guide Examples",
                ReadSQLStatement,
                ReadStoredProcWithParams,
                ReadSQLOrSprocWithNamedParams,
                ReadDataAsObjects,
                ReadDataAsXML,
                ReadScalarValue,
                ReadDataAsynchronously,
                ReadObjectsAsynchronously,
                UpdateWithCommand,
                FillAndUpdateDataset,
                UseConnectionTransaction,
                UseTransactionScope).Run();
        }
 
        [Description("Return rows using a SQL statement with no parameters")]
        static void ReadSQLStatement()
        {
            // Call the ExecuteReader method by specifying the command type
            // as a SQL statement, and passing in the SQL statement
            using (IDataReader reader = namedDB.ExecuteReader(CommandType.Text, "SELECT TOP 1 * FROM OrderList"))
            {
                DisplayRowValues(reader);
            }
        }
        [Description("Return rows using a stored procedure with parameters")]
        static void ReadStoredProcWithParams()
        {
            // Call the ExecuteReader method with the stored procedure
            // name and an Object array containing the parameter values
            using (IDataReader reader = defaultDB.ExecuteReader("ListOrdersByState", new object[] { "Colorado" }))
            {
                DisplayRowValues(reader);
            }
        }
 
        [Description("Return rows using a SQL statement or stored procedure with named parameters")]
        static void ReadSQLOrSprocWithNamedParams()
        {
            // Read data with a SQL statement that accepts one parameter
            string sqlStatement = "SELECT TOP 1 * FROM OrderList WHERE State LIKE @state";
            // Create a suitable command type and add the required parameter
            using (DbCommand sqlCmd = defaultDB.GetSqlStringCommand(sqlStatement))
            {
                defaultDB.AddInParameter(sqlCmd, "state", DbType.String, "New York");
                // Call the ExecuteReader method with the command
                using (IDataReader sqlReader = namedDB.ExecuteReader(sqlCmd))
                {
                    Console.WriteLine("Results from executing SQL statement:");
                    DisplayRowValues(sqlReader);
                }
            }
            // Read data with a stored procedure that accepts one parameter
            string storedProcName = "ListOrdersByState";
            // Create a suitable command type and add the required parameter
            using (DbCommand sprocCmd = defaultDB.GetStoredProcCommand(storedProcName))
            {
                defaultDB.AddInParameter(sprocCmd, "state", DbType.String, "New York");
                // Call the ExecuteReader method with the command
                using (IDataReader sprocReader = namedDB.ExecuteReader(sprocCmd))
                {
                    Console.WriteLine("Results from executing stored procedure:");
                    DisplayRowValues(sprocReader);
                }
            }
        }
 
        [Description("Return data as a sequence of objects using a stored procedure")]
        static void ReadDataAsObjects()
        {
            // Create an object array and populate it with the required parameter values
            object[] paramArray = new object[] { "%bike%" };
            // Create and execute a sproc accessor that uses default parameter and output mappings
            var productData = defaultDB.ExecuteSprocAccessor<Product>("GetProductList", paramArray);
            // Perform a client-side query on the returned data
            // Be aware that the orderby and filtering is happening on the client, not the database
            var results = from productItem in productData
                          where productItem.Description != null
                          orderby productItem.Name
                          select new { productItem.Name, productItem.Description };
            // Display the results
            foreach (var item in results)
            {
                Console.WriteLine("Product Name: {0}", item.Name);
                Console.WriteLine("Description: {0}", item.Description);
                Console.WriteLine();
            }
        }
 
        [Description("Return data as an XML fragment using a SQL Server XML query")]
        static void ReadDataAsXML()
        {
            // Specify a SQL query that returns XML data
            string xmlQuery = "SELECT * FROM OrderList WHERE State = @state FOR XML AUTO";
            // Create a suitable command type and add the required parameter
            // NB: ExecuteXmlReader is only available for SQL Server databases
            using (DbCommand xmlCmd = sqlServerDB.GetSqlStringCommand(xmlQuery))
            {
                xmlCmd.Parameters.Add(new SqlParameter("state", "Colorado"));
                using (XmlReader reader = sqlServerDB.ExecuteXmlReader(xmlCmd))
                {
                    // Iterate through the elements in the XmlReader
                    while (!reader.EOF)
                    {
                        if (reader.IsStartElement())
                        {
                            Console.WriteLine(reader.ReadOuterXml());
                        }
                    }
                }
            }
        }
 
        [Description("Return a single scalar value from a SQL statement or stored procedure")]
        static void ReadScalarValue()
        {
            // Create a suitable command type for a SQL statement
            using (DbCommand sqlCmd = defaultDB.GetSqlStringCommand("SELECT [Name] FROM States"))
            {
                // Call the ExecuteScalar method of the command
                Console.WriteLine("Result using a SQL statement: {0}",
                                   defaultDB.ExecuteScalar(sqlCmd).ToString());
            }
            // Create a suitable command type for a stored procedure
            using (DbCommand sprocCmd = defaultDB.GetStoredProcCommand("GetStatesList"))
            {
                // Call the ExecuteScalar method of the command
                Console.WriteLine("Result using a stored procedure: {0}",
                                   defaultDB.ExecuteScalar(sprocCmd).ToString());
            }
        }
 
        [Description("Execute a command that retrieves data asynchronously")]
        static void ReadDataAsynchronously()
        {
            if (!SupportsAsync(asyncDB)) return;
 
            using (var doneWaitingEvent = new ManualResetEvent(false))
            using (var readCompleteEvent = new ManualResetEvent(false))
            {
                try
                {
                    // Create command to execute stored procedure and add parameters
                    DbCommand cmd = asyncDB.GetStoredProcCommand("ListOrdersSlowly");
                    asyncDB.AddInParameter(cmd, "state", DbType.String, "Colorado");
                    asyncDB.AddInParameter(cmd, "status", DbType.String, "DRAFT");
                    // Execute the query asynchronously specifying the command and the
                    // expression to execute when the data access process completes.
                    asyncDB.BeginExecuteReader(cmd,
                        asyncResult =>
                        {
                            // Lambda expression executed when the data access completes.
                            doneWaitingEvent.Set();
                            try
                            {
                                using (IDataReader reader = asyncDB.EndExecuteReader(asyncResult))
                                {
                                    Console.WriteLine();
                                    Console.WriteLine();
                                    DisplayRowValues(reader);
                                }
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine("Error after data access completed: {0}", ex.Message);
                            }
                            finally
                            {
                                readCompleteEvent.Set();
                            }
                        }, null);
 
                    // Display waiting messages to indicate executing asynchronouly
                    while (!doneWaitingEvent.WaitOne(1000))
                    {
                        Console.Write("Waiting... ");
                    }
 
                    // Allow async thread to write results before displaying "continue" prompt
                    readCompleteEvent.WaitOne();
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Error while starting data access: {0}", ex.Message);
                }
            }
        }
 
        [Description("Execute a command that retrieves data as objects asynchronously")]
        static void ReadObjectsAsynchronously()
        {
            if (!SupportsAsync(asyncDB)) return;
 
            using (var doneWaitingEvent = new ManualResetEvent(false))
            using (var readCompleteEvent = new ManualResetEvent(false))
            {
                try
                {
                    // Create an object array and populate it with the required parameter values.
                    object[] paramArray = new object[] { "%bike%", 20 };
 
                    // Create the accessor. This example uses the simplest overload.
                    var accessor = asyncDB.CreateSprocAccessor<Product>("GetProductsSlowly");
 
                    // Execute the accessor asynchronously specifying the callback expression,
                    // the existing accessor as the AsyncState, and the parameter values array.
                    accessor.BeginExecute(
                        asyncResult =>
                        {
                            // Lambda expression executed when the data access completes.
                            doneWaitingEvent.Set();
                            try
                            {
                                // Accessor is available via the asyncResult parameter
                                var acc = (DataAccessor<Product>)asyncResult.AsyncState;
 
                                // Obtain the results from the accessor.
                                var productData = acc.EndExecute(asyncResult);
 
                                // Perform a client-side query on the returned data.
                                // Be aware that the orderby and filtering is happening 
                                // on the client, not inside the database.
                                var results = from productItem in productData
                                              where productItem.Description != null
                                              orderby productItem.Name
                                              select new { productItem.Name, productItem.Description };
 
                                // Display the results
                                Console.WriteLine();
                                Console.WriteLine();
                                foreach (var item in results)
                                {
                                    Console.WriteLine("Product Name: {0}", item.Name);
                                    Console.WriteLine("Description: {0}", item.Description);
                                    Console.WriteLine();
                                }
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine("Error after data access completed: {0}", ex.Message);
                            }
                            finally
                            {
                                readCompleteEvent.Set();
                            }
                        }, accessor, paramArray);
 
                    // Display waiting messages to indicate executing asynchronously.
                    while (!doneWaitingEvent.WaitOne(1000))
                    {
                        Console.Write("Waiting... ");
                    }
                    // Allow async thread to write results before displaying "continue" prompt.
                    readCompleteEvent.WaitOne();
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Error while starting data access: {0}", ex.Message);
                }
            }
        }
 
        [Description("Update data using a Command object")]
        static void UpdateWithCommand()
        {
            string oldDescription = "Carries 4 bikes securely; steel construction, fits 2\" receiver hitch.";
            string newDescription = "Bikes tend to fall off after a few miles.";
            Console.WriteLine("Contents of row before update:");
            DisplayRowValues(defaultDB.ExecuteReader(CommandType.Text, "SELECT * FROM Products WHERE [Id] = 84"));
            // Create command to execute stored procedure and add parameters
            DbCommand cmd = defaultDB.GetStoredProcCommand("UpdateProductsTable");
            defaultDB.AddInParameter(cmd, "productID", DbType.Int32, 84);
            defaultDB.AddInParameter(cmd, "description", DbType.String, newDescription);
            // Execute query and check if one row was updated
            if (defaultDB.ExecuteNonQuery(cmd) == 1)
            {
                Console.WriteLine("Contents of row after first update:");
                DisplayRowValues(defaultDB.ExecuteReader(CommandType.Text, "SELECT * FROM Products WHERE [Id] = 84"));
            }
            else
            {
                Console.WriteLine("ERROR: Could not update just one row.");
            }
            // Change the value of the second parameter
            defaultDB.SetParameterValue(cmd, "description", oldDescription);
            // Execute query and check if one row was updated
            if (defaultDB.ExecuteNonQuery(cmd) == 1)
            {
                Console.WriteLine("Contents of row after second update:");
                DisplayRowValues(defaultDB.ExecuteReader(CommandType.Text, "SELECT * FROM Products WHERE [Id] = 84"));
            }
            else
            {
                Console.WriteLine("ERROR: Could not update just one row.");
            }
        }
 
        [Description("Fill a DataSet and update the source data")]
        static void FillAndUpdateDataset()
        {
            string selectSQL = "SELECT Id, Name, Description FROM Products WHERE Id > 90";
            string addSQL = "INSERT INTO Products (Name, Description) VALUES (@name, @description);";
            string updateSQL = "UPDATE Products SET Name = @name, Description = @description WHERE Id = @id";
            string deleteSQL = "DELETE FROM Products WHERE Id = @id";
 
            // Fill a DataSet from the Products table using the simple approach
            DataSet simpleDS = defaultDB.ExecuteDataSet(CommandType.Text, selectSQL);
            DisplayTableNames(simpleDS, "ExecuteDataSet");
            simpleDS = null;
            // Fill a DataSet from the Products table using the LoadDataSet method
            // This allows you to specify the name(s) for the table(s) in the DataSet
            DataSet loadedDS = new DataSet("ProductsDataSet");
            defaultDB.LoadDataSet(CommandType.Text, selectSQL, loadedDS, new string[] { "Products" });
            DisplayTableNames(loadedDS, "LoadDataSet");
            // Update some data in the rows of the DataSet table
            DataTable dt = loadedDS.Tables["Products"];
            dt.Rows[0].Delete();
            object[] rowData = new object[] { -1, "A New Row", "Added to the table at " + DateTime.Now.ToShortTimeString() };
            dt.Rows.Add(rowData);
            rowData = dt.Rows[1].ItemArray;
            rowData[2] = "A new description at " + DateTime.Now.ToShortTimeString();
            dt.Rows[1].ItemArray = rowData;
            DisplayRowValues(dt);
            // Create the commands to update the original table in the database
            DbCommand insertCommand = defaultDB.GetSqlStringCommand(addSQL);
            defaultDB.AddInParameter(insertCommand, "name", DbType.String, "Name", DataRowVersion.Current);
            defaultDB.AddInParameter(insertCommand, "description", DbType.String, "Description", DataRowVersion.Current);
            DbCommand updateCommand = defaultDB.GetSqlStringCommand(updateSQL);
            defaultDB.AddInParameter(updateCommand, "name", DbType.String, "Name", DataRowVersion.Current);
            defaultDB.AddInParameter(updateCommand, "description", DbType.String, "Description", DataRowVersion.Current);
            defaultDB.AddInParameter(updateCommand, "id", DbType.String, "Id", DataRowVersion.Original);
            DbCommand deleteCommand = defaultDB.GetSqlStringCommand(deleteSQL);
            defaultDB.AddInParameter(deleteCommand, "id", DbType.Int32, "Id", DataRowVersion.Original);
            // Apply the updates in the DataSet to the original table in the database
            int rowsAffected = defaultDB.UpdateDataSet(loadedDS, "Products",
                               insertCommand, updateCommand, deleteCommand,
                               UpdateBehavior.Standard);
            Console.WriteLine("Updated a total of {0} rows in the database.", rowsAffected);
        }
 
        [Description("Use a connection-based transaction")]
        static void UseConnectionTransaction()
        {
            Console.WriteLine("Contents of rows before update:");
            Console.WriteLine();
            DisplayRowValues(defaultDB.ExecuteReader(CommandType.Text, "SELECT * FROM Products WHERE [Id] = 53"));
            DisplayRowValues(defaultDB.ExecuteReader(CommandType.Text, "SELECT * FROM Products WHERE [Id] = 84"));
            Console.WriteLine(MenuDrivenApplication.Underline);
            string newRow53Value = "Third and little fingers tend to get cold.";
            string newRow84Value = "Bikes tend to fall off after a few miles.";
            // Must specifically create the connection for the command
            // to be able to create a transaction for the operations.
            using (DbConnection con = defaultDB.CreateConnection())
            {
                // By default, data access methods will create and manage the connection.
                // When the connection is created manually, it must be managed in the code.
                con.Open();
                // Create a transaction on the open connection for the operations
                using (DbTransaction trans = con.BeginTransaction())
                {
                    // Create command to execute stored procedure and add parameters
                    DbCommand cmd = defaultDB.GetStoredProcCommand("UpdateProductsTable");
                    defaultDB.AddInParameter(cmd, "productID", DbType.Int32, 53);
                    defaultDB.AddInParameter(cmd, "description", DbType.String, newRow53Value);
                    // Execute two updates and check if each updated one row as expected,
                    // specifying that they execute within the current transaction
                    if (defaultDB.ExecuteNonQuery(cmd, trans) == 1)
                    {
                        Console.WriteLine("Updated row with ID = 53 to '{0}'.", newRow53Value);
                    }
                    else
                    {
                        Console.WriteLine("ERROR: Could not update just one row.");
                    }
                    // Change the values in the command parameters
                    defaultDB.SetParameterValue(cmd, "productID", 84);
                    defaultDB.SetParameterValue(cmd, "description", newRow84Value);
                    if (defaultDB.ExecuteNonQuery(cmd, trans) == 1)
                    {
                        Console.WriteLine("Updated row with ID = 84 to '{0}'.", newRow84Value);
                    }
                    else
                    {
                        Console.WriteLine("ERROR: Could not update just one row.");
                    }
                    // Roll back the transaction
                    trans.Rollback();
                }
                Console.WriteLine(MenuDrivenApplication.Underline);
                Console.WriteLine("Contents of row after rolling back transaction:");
                Console.WriteLine();
                DisplayRowValues(defaultDB.ExecuteReader(CommandType.Text, "SELECT * FROM Products WHERE [Id] = 53"));
                DisplayRowValues(defaultDB.ExecuteReader(CommandType.Text, "SELECT * FROM Products WHERE [Id] = 84"));
            }
        }
 
        [Description("Use a TransactionScope for a distributed transaction")]
        static void UseTransactionScope()
        {
            Console.WriteLine("Contents of rows before update:");
            Console.WriteLine();
            DisplayRowValues(defaultDB.ExecuteReader(CommandType.Text, "SELECT * FROM Products WHERE [Id] = 53"));
            DisplayRowValues(defaultDB.ExecuteReader(CommandType.Text, "SELECT * FROM Products WHERE [Id] = 84"));
            Console.WriteLine(MenuDrivenApplication.Underline);
            string newRow53Value = "Third and little fingers tend to get cold.";
            string newRow84Value = "Bikes tend to fall off after a few miles.";
            // Create a transaction scope for the distributed operations
            using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew))
            {
                // Create command to execute stored procedure and add parameters
                DbCommand cmdA = defaultDB.GetStoredProcCommand("UpdateProductsTable");
                defaultDB.AddInParameter(cmdA, "productID", DbType.Int32, 53);
                defaultDB.AddInParameter(cmdA, "description", DbType.String, newRow53Value);
                // Execute first update and check if it updated one row as expected.
                // No distributed transaction will be created for this operation.
                if (defaultDB.ExecuteNonQuery(cmdA) == 1)
                {
                    Console.WriteLine("Updated row with ID = 53 to '{0}'.", newRow53Value);
                }
                else
                {
                    Console.WriteLine("ERROR: Could not update just one row.");
                }
                // Wait for a keypress. At this point there is no distributed transaction.
                // Open Component Services in MMC and view Local DTC Transaction List.
                Console.WriteLine("No distributed transaction. Press any key to continue...");
                Console.WriteLine();
                Console.ReadKey(true);
                // Create second command to execute stored procedure and add parameters.
                // Must use a different connection string to force creation of a new connection.
                DbCommand cmdB = asyncDB.GetStoredProcCommand("UpdateProductsTable");
                asyncDB.AddInParameter(cmdB, "productID", DbType.Int32, 84);
                asyncDB.AddInParameter(cmdB, "description", DbType.String, newRow84Value);
                // Execute second update and check if it updated one row as expected.
                // This will automatically create a new distributed transaction and
                // enrol both this and the original command.
                if (asyncDB.ExecuteNonQuery(cmdB) == 1)
                {
                    Console.WriteLine("Updated row with ID = 84 to '{0}'.", newRow84Value);
                }
                else
                {
                    Console.WriteLine("ERROR: Could not update just one row.");
                }
                // Wait for a keypress. At this point there is a new distributed transaction.
                Console.WriteLine("New distributed transaction created. Press any key to continue...");
                Console.ReadKey(true);
            }
            // TransactionScope now disposed without executing TransactionScope.Complete
            // method to commit changes. Therefore changes will be rolled back automatically.
            Console.WriteLine(MenuDrivenApplication.Underline);
            Console.WriteLine("Contents of row after disposing TransactionScope:");
            Console.WriteLine();
            DisplayRowValues(defaultDB.ExecuteReader(CommandType.Text, "SELECT * FROM Products WHERE [Id] = 53"));
            DisplayRowValues(defaultDB.ExecuteReader(CommandType.Text, "SELECT * FROM Products WHERE [Id] = 84"));
        }
 
        #region Auxiliary routines
 
        private static bool SupportsAsync(Database db)
        {
            if (db.SupportsAsync)
            {
                Console.WriteLine("Database supports asynchronous operations");
                return true;
            }
            Console.WriteLine("Database does not support asynchronous operations");
            return false;
        }
 
        private static void DisplayRowValues(DataTable table)
        {
            Console.WriteLine(MenuDrivenApplication.Underline);
            Console.WriteLine("Rows in the table named '{0}':", table.TableName);
            Console.WriteLine();
            DisplayRowValues(table.CreateDataReader());
        }
 
        private static void DisplayRowValues(IDataReader reader)
        {
            while (reader.Read())
            {
                for (int i = 0; i < reader.FieldCount; i++)
                {
                    Console.WriteLine("{0} = {1}", reader.GetName(i), reader[i].ToString());
                }
                Console.WriteLine();
            }
        }
 
        private static void DisplayTableNames(DataSet ds, string methodName)
        {
            Console.WriteLine("Tables in the DataSet obtained using the {0} method:", methodName);
            foreach (DataTable t in ds.Tables)
            {
                Console.WriteLine(" - Table named '{0}' contains {1} rows.", t.TableName, t.Rows.Count);
            }
            Console.WriteLine();
        }
 
        #endregion
    }
}