2012年10月31日 星期三

[Sql Server] 使用JOIN的資料來做UPDATE


UPDATE XXXX
SET
欄位一=y.欄位A,
欄位二=y.欄位B
FROM
XXXX INNER JOIN
(
   SELECT * FROM YYYY
) y
ON
XXXX.key欄位一 = y.key欄位一



[C#] Template 樣板模式


Design Pattern : Template

1.      What is Template
記得小時候,寒假開始前,老師一定會叫我們過完寒假要寫一篇出遊的作文。
然而過完寒假後,一定是沒有寫 XD
這時候我們幾個死黨就會去找班上功課最好的同學A,準備把他的作文拿來抄一抄。
A
「你們大家全部抄我的,一模一樣一定會被老師發現。」
於是A拿起他的作文,在以下的地方改成空格,要我們自行填入:

作文題目:寒假出遊
我今天去___,看到很多___,中午和家人一起吃___

沒錯! 這個就是我們最早使用的Template!
也就是只要先寫好父類別的方法,(寒假出遊
這個方法裡面呼叫了自己的一些abstract方法以及決定執行順序。(我今天去看到很多
接著只要定義一些子類別繼承父類別,再來override這些abstract方法即可。

例如 我就可以把這篇作文寫成:
我今天去動物園,看到很多動物,中午和家人一起吃肯德基

2.      Definition

以下是參考前輩此篇文章的描述:
u  定義好method的內容,當作範本,讓其他程式使用。
u  透過繼承的方式,讓子類別能夠實作不同的邏輯區塊。
u  在父類別的method中,依相同順序執行不同區塊的邏輯。
u  所以不同的子類別,能夠實作各自的方法細節,然後統一利用父類別的final method,來執行任務



3.      An Example
實務上,常常對後端資料庫做查詢,如果有多種資料庫(如MS sql Server, Oracle…),查詢的流程其實一樣,只是細節可能不同(如資料庫連線設定,開啟關閉連線…etc
所以我們利用Template來實作資料庫查詢的類別。




u  定義父類別 ConnModel
備註1. DoQuery 就是決定查詢的步驟的方法。
備註2.可以使用mark掉的那些程式碼,由宣告的子類別來進一步控制父類別的方法。  例如:子類別不須要關閉連線這個步驟,則將isCloseConn這個標記設定為false即可。

   public abstract class ConnModel
   {
     private SqlConnection sqlConn;  //資料庫物件

        protected abstract void Setup(); //做資料庫連線設定
        protected abstract void StartConn(); //開始連線
        protected abstract DataTable Query(String sSql); //查詢
        protected abstract void EndConn(); //關閉連線

        //public bool isCloseConn = true; //是否關閉連線 (預設:是)

        /// <summary>
        /// 查詢
        /// </summary>
        ///<param name="sSql">SQL指令</param>
        public DataTable DoQuery(String sSql)
        {
            try
            {
                Setup();
                StartConn();
                return Query(sSql);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                //if (isCloseConn == true)   //檢查是否自動關閉連線
                //{
                    EndConn();
                //}

            }
        }
    }

u  定義第一個MS Sql Server子類別 MSSql
這邊可以很清楚看到,這個子類別只是將繼承的ConnModel裡面的abstract方法override成自己的內容。

  public class MSSql : ConnModel
   {
     /// <summary>
     /// 開始連線
       /// </summary>
        protected override void StartConn()
        {
            Console.WriteLine("建立MS Sql Server連線!");
        }
        /// <summary>
        /// 做資料庫連線設定
        /// </summary>
        protected override void Setup()
        {
            Console.WriteLine("資料庫連線設定!");
        }
        /// <summary>
        /// 查詢
        /// </summary>
        /// <param name="sSql"></param>
        /// <returns></returns>
        protected override DataTable Query(String sSql)
        {
            Console.WriteLine("開始查詢MS Sql Server後端資料庫!");
            return null;
        }
        /// <summary>
        /// 關閉連線
        /// </summary>
        protected override void EndConn()
        {
            Console.WriteLine("關閉MS Sql Server資料庫連線!");
        }
       }

u  定義第二個Oracle子類別 Oracle
就不列出程式碼了,只是把上面輸出的部分稍微修改。

u  主程式(mark掉的部分,就是備註2.提到的東西)
Oracle _oracle = new Oracle();
String sSql_oracle = "SELECT 1 FROM DUAL";
//_oracle.isCloseConn = true;
_oracle.DoQuery(sSql_oracle);
_oracle = null;

MSSql _mssql = new MSSql();
String sSql_ms = "SELECT 1 ";
//_mssql.isCloseConn = false;
_mssql.DoQuery(sSql_ms);
_mssql = null;

u  執行結果
資料庫連線設定!
建立Oracle連線!
開始查詢Oracle後端資料庫!
關閉Oracle資料庫連線!

資料庫連線設定!
建立MS Sql Server連線!
開始查詢MS Sql Server後端資料庫!
關閉MS Sql Server資料庫連線!


4.      至於優缺點,我參考書上的內容~
優點:符合OCP,易於維護。
缺點:步驟寫在父類別,但是步驟的邏輯寫在子類別,造成程式碼不易閱讀。






2012年10月12日 星期五

Design Pattern : Decorator 裝飾模式 (1)

Decorator

使用時機:
A.系統需要新增新功能,但不想用繼承造成系統的子類別過多。
B.類別需要「動態」附加新功能。

方法:
1.  定義一個Interface和實作它的Class
2.  定義一個Abstract Class : Decorator 實作 interface
3.  定義其他裝飾類別封裝實體化Decorator類別,並覆寫(override)原有的方法。
4.  使用裝飾類別~ 宣告並取代原有的物件。

範例:
假設一個遊戲中,主角可以拿槍射擊敵人。
所以我們定義一個槍的interface : IGun class : CGun ,這是遊戲中最普通的槍。
隨著遊戲升級,武器可以加裝狙擊鏡Scope或是裝填雷射彈藥Laser ammo
他們所對應的開火情況便不相同。


1.  定義一個Interface和實作它的Class
/// <summary>
/// Abstract Class : CGun
/// </summary>
public interface IGun
{
    // 槍名
    String GunName { get; set;  }
    // 開火
    void Fire();
}

/// <summary>
    /// CGun實作IGun
    /// </summary>
    public class CGun : IGun
    {
        String sGunName;

        //建構子
        public CGun(String _GunName)
        {
            sGunName = _GunName;
        }

        // 槍名
        public String GunName
        {
            get { return sGunName; }
            set { sGunName = value; }
        }

        // 開火
        public void Fire()
        {
            Console.WriteLine(
                String.Format("{0}開火! ", sGunName));
        }
    }

2.  定義一個Abstract Class : Decorator 實作 interface

/// <summary>
    /// 實作IGun Decorator
    /// </summary>
   public abstract class Decorator : IGun
    {
        public String sGunName;
        protected CGun cGun = null//重要:需在此宣告一個protected CGun物件

        //透過建構子傳遞被修飾者
        public Decorator( CGun _cGun)
        {
            this.cGun = _cGun;
        }

        // 槍名
        public String GunName
        {
            get { return sGunName; }
            set { sGunName = value; }
        }

        //委託給被修飾者執行
        public virtual void Fire()
        {
            if (cGun != null)
            {
                this.cGun.Fire();
            }
        }
    }


3.  定義其他裝飾類別封裝實體化Decorator類別,並覆寫(override)原有的方法。

(A)
加裝狙擊鏡的裝飾類別
/// <summary>
    /// 可以加裝狙擊鏡的 裝飾類別
    /// </summary>
    public class CScopeDecorator : Decorator  //重要:實體化Decorator
    {
        //建構子 : 繼承基底類別的建構子
        public CScopeDecorator(CGun _cGun)
            : base(_cGun)
        {
            //建構子沒有變化...
        }

        //重寫父類別的Fire方法
        public override void Fire()
        {
            Console.WriteLine(
                String.Format("用裝了狙擊鏡的{0}開火! ", cGun.GunName ));
        }
}

(B)
裝填雷射彈藥的裝飾類別
/// <summary>
    /// 可以加裝雷射彈藥的 裝飾類別
    /// </summary>
    public class CLaserDecorator : Decorator
    {
        //建構子 : 繼承基底類別的建構子,但是改掉原本的槍名
        public CLaserDecorator(CGun _cGun)
            : base(_cGun)
        {
            //建構子有變化...
            _cGun.GunName = "Super Laser Rifle";
        }

        //重寫父類別的Fire方法
        public override void Fire()
        {
            Console.WriteLine(
                String.Format("用裝了雷射彈藥的{0}開火! ", cGun.GunName ));

            OverHeat();
        }

        //新增方法:槍管過熱
        private void OverHeat()
        {
            Console.WriteLine(
                String.Format("警告! {0} 槍管過熱。 ", cGun.GunName));
        }
}


4.  使用裝飾類別~ 宣告並取代原有的物件。


//宣告一個 CGun物件
IGun myGun = new CGun("Desert Eagle");
myGun.Fire();

//CScopeDecorator 裝飾原本的 CGun物件
myGun = new CScopeDecorator((CGun)myGun);
myGun.Fire();

//CLaserDecorator 裝飾原本的 CGun物件
IGun myGun2 = new CLaserDecorator
(
  new CGun("???")
);
   myGun2.Fire();


顯示結果
:

Desert Eagle
開火!
用裝了狙擊鏡的Desert Eagle開火!
用裝了雷射彈藥的Super Laser Rifle開火!
警告! Super Laser Rifle 槍管過熱。