2010年2月5日 星期五

找出指定年度的每個月天數之 T SQL


如何找出上個月的最後一天
declare @dt datetime

set @dt='2009/02/15'

--找出上個月最後一天

select convert(datetime,convert(char(7),@dt,111)+'/01')-1

--找出該月第一天

select convert(char(7),@dt,111)+'/01'


如何找出指定年度的每個月天數
declare @year varchar(4) --假設年度

declare @month int --計算月份之用

declare @dt1 datetime --計算該月第一天

declare @dt2 datetime --計算該月最後一天

set @year='2007'

set @month=1

while @month<=12

 begin

  select @dt1=convert(datetime,@year+'/'+convert(varchar(2),@month)+'/01') --找出該月第一天

  set @dt2=DateAdd(mm,1,@dt1)-1 --找出該月最後一天

  select @year '年份',@month '月份',datediff(dd,@dt1,@dt2)+1 '天數' --輸出結果

  set @month=@month+1

 end


2010年2月4日 星期四

實作ASP.NET MVC SendMail功能


今天研究在ASP.NET MVC於Action作完後,發mail到指定之User的方法,
在網路上Google一下,參考此篇文章:如何發送內嵌圖片的 E-mail ( Inline Attachment ) ,將其實作出來。

1.實作一個SendMail類別,程式碼如下:
using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Net.Mail;

using System.IO;



namespace IPRO.Ext

{

    public class SendMail

    {

        #region private fields

        private string _fromName;

        private string _fromAddress;

        private string _toName;

        private string _toAddress;

        private string _smtpServer;

        private int _smtpPort;

        private string _subject;

        private string _body;

        private string[] _filePath;

        private string _mailEncoding = "utf-8";

        #endregion



        #region construtor

        public SendMail(string fromName, string fromAddress, string toName,

                        string toAddress, string subject, string body,

                        string[] filePath, string smtpServer, int smtpPort)

        {

            this._fromName = fromName;

            this._fromAddress = fromAddress;

            this._toName = toName;

            this._toAddress = toAddress;

            this._subject = subject;

            this._body = body;

            this._filePath = filePath;

            this._smtpServer = smtpServer;

            this._smtpPort = smtpPort;

        }

        #endregion



        #region public method

        public void Send()

        {

            MailAddress from;

            MailAddress to;

            if (string.IsNullOrEmpty(_fromName))

            {

                from = new MailAddress(_fromAddress);

            }

            else

            {

                from = new MailAddress(_fromAddress, _fromName, Encoding.GetEncoding(_mailEncoding));

            }



            if (string.IsNullOrEmpty(_toName))

            {

                to = new MailAddress(_toAddress);

            }

            else

            {

                to = new MailAddress(_toAddress, _toName, Encoding.GetEncoding(_mailEncoding));

            }



            MailMessage message = new MailMessage(from, to);

            if(string.IsNullOrEmpty(_subject))

            {

                _subject = "郵件主旨";

            }

            message.Subject = _subject;

            message.SubjectEncoding = Encoding.GetEncoding(_mailEncoding);



            if(string.IsNullOrEmpty(_body))

            {

                _body = "郵件內容";

            }

            message.Body = _body;

            message.BodyEncoding = Encoding.GetEncoding(_mailEncoding);

            message.IsBodyHtml = true;

            message.Priority = MailPriority.High;



            //設定附件檔案(Attachment)

            if (_filePath.Length > 0)

            {

                for (int i = 0; i < _filePath.Length; i++)

                {

                    Attachment attachment = new Attachment(_filePath[i]);

                    attachment.Name = Path.GetFileName(_filePath[i]);

                    attachment.NameEncoding = Encoding.GetEncoding(_mailEncoding);

                    attachment.TransferEncoding = System.Net.Mime.TransferEncoding.Base64;

                    // 設定該附件為一個內嵌附件(Inline Attachment)

                    attachment.ContentDisposition.Inline = true;

                    attachment.ContentDisposition.DispositionType = System.Net.Mime.DispositionTypeNames.Inline;

                    message.Attachments.Add(attachment);

                }

            }



            if (_smtpPort == 0)

            {

                _smtpPort = 25;

            }



            if (string.IsNullOrEmpty(_smtpServer))

            {

                _smtpServer = "";

            }



            SmtpClient smtpClient = new SmtpClient(_smtpServer, _smtpPort);

            try

            {

                smtpClient.Send(message);

                System.Diagnostics.Debug.WriteLine(DateTime.Now.ToString() + " 寄信成功!!!");

            }

            catch

            {

                System.Diagnostics.Debug.WriteLine(DateTime.Now.ToString() + " 寄信失敗!!!");

            }

        }

        #endregion

    }

}


2.於Action中加入SendMail功能:
                SendMail mail = new SendMail("haha", "haha@gmail.com",
                                             "haha", "haha@yahoo.com.tw", "主旨",
                                             "內容", new string[] { },
                                             "smtp.gmail.com", 25);
                mail.Send();

ASP.NET MVC Ajax.ActionLink with Image

2010年1月31日 星期日

在ASP.NET中觀察LINQ to SQL所產生的T-SQL語法


接連在好幾個小專案裡用了LINQ to SQL,慢慢掌握要領,煎、煮、炒、炸查詢、新增、修改、刪除,各種料理操作都已能手到擒來,就愈發感受到它的便利性。

說穿了,LINQ to SQL只不過是ORM的一種具體實踐,並無深奧學問,之所以用來得心應手、讓人驚豔,不外乎是在與Visual Studio 2008整合深度上佔了優勢。以一個開發者的角度而言,我不在乎這對其他解決方案是否公允? 也不關心這類綁標圖利是否會有爭議? 給我方便的開發工具,其餘免談。

過去曾用ADO/ADO.NET開發過很長一段時間,在效能議題上下過一些功夫。切換到LINQ to SQL後,完全不沾SqlConnection、SqlCommand、SqlParameter就能搞定與資料庫相關的大小事,固然讓人心曠神怡;但過去對效能斤斤計較,換到LINQ,我還是常常懷疑LINQ所自動轉譯成的T-SQL到底長得什麼德性,會不會荒腔走板、效能低落?

要解除疑慮,最直接有效的方法就是檢查LINQ to SQL所產出的T-SQL語法,沒有什麼比眼見為憑更具說服力了! System.Data.Linq.DataContext類別有個屬性叫Log,我們可以接上一個TextWriter,DataContext會在執行T-SQL指令時,輸出實際使用的T-SQL語法、參數細節,提供極佳的觀察與偵錯資訊。

不過,如MSDN文件所示,能找到的Log應用範例幾乎都是接上Console.Out適用於Console Application,如果我們是在網頁中執行,想要如同System.Diagnositcs.Debug.WriteLine一般輸出在 VS2008的偵錯輸出視窗,該怎麼做呢?

我找到了Kris Vadermotten寫的DebuggerWriter類別,可以滿足以上的需求:

using System;

using System.Diagnostics;

using System.Globalization;

using System.IO;

using System.Text;



    /// <summary>

    /// Original by Kris Vadermotten: http://www.u2u.info/Blogs/Kris/Lists/Posts/Post.aspx?ID=11 <br />

    /// Remixed by Jeffrey Lee, 2009-07-11 http://blog.darkthread.net<br />

    /// Implements a <see cref="TextWriter"/> for writing information to the debugger log. 

    /// </summary>

    /// <seealso cref="Debugger.Log"/>

    public class DebuggerWriter : TextWriter

    {

        private bool isOpen;

        private static UnicodeEncoding encoding =

            new UnicodeEncoding(false, false);

        public int Level { get; private set; }

        public string Category { get; private set; }



        /// <summary>

        /// Initializes a new instance of the <see cref="DebuggerWriter"/> class.

        /// </summary>

        public DebuggerWriter()



            : this(0, Debugger.DefaultCategory) { }



        /// <summary>

        /// Initializes a new instance of the <see cref="DebuggerWriter"/> class with the specified level and category.

        /// </summary>

        /// <param name="level">A description of the importance of the messages.</param>

        /// <param name="category">The category of the messages.</param>

        public DebuggerWriter(int level, string category)



            : this(level, category, CultureInfo.CurrentCulture) { }



        /// <summary>

        /// Initializes a new instance of the <see cref="DebuggerWriter"/> class with the specified level, category and format provider.

        /// </summary>

        /// <param name="level">A description of the importance of the messages.</param>

        /// <param name="category">The category of the messages.</param>

        /// <param name="formatProvider">An <see cref="IFormatProvider"/> object that controls formatting.</param>

        public DebuggerWriter(int level, string category, IFormatProvider formatProvider)

            : base(formatProvider)

        {

            Level = level;

            Category = category;

            this.isOpen = true;

        }



        protected override void Dispose(bool disposing)

        {

            isOpen = false;

            base.Dispose(disposing);

        }



        public override void Write(char value)



        {

            if (!isOpen)

                throw new ObjectDisposedException(null);

            Debugger.Log(Level, Category, value.ToString());

        }



        public override void Write(string value)



        {

            if (!isOpen)

                throw new ObjectDisposedException(null);

            if (value != null)

                Debugger.Log(Level, Category, value);

        }

        

        public override void Write(char[] buffer, int index, int count)



        {

            if (!isOpen)

                throw new ObjectDisposedException(null);

            if (buffer == null || index < 0 || count < 0 || buffer.Length - index < count)

                base.Write(buffer, index, count); // delegate throw exception to base class

            Debugger.Log(Level, Category, new string(buffer, index, count));

        }



        public override Encoding Encoding



        {

            get { return encoding; }

        }

    }


將以上的DebuggerWriter.cs放入App_Code,然後youDataContext.Log = new DebuggerWriter(),設定Breakpoint,再一列一列Debug,你就可以觀察到何時LINQ to SQL會執行什麼樣的T-SQL指令,甚至包含參數值等細節,很犀利吧?


以上的範例,其實會觸發兩次SQL查詢,若要再精簡,可以改寫成:

var q = (from o in db.Players
where o.ID < 20
select o).ToList();

大家實際動手玩玩便知。

【2009-07-12補充】艾小克提供可以整合在VS2008裡,在開發階段檢視查詢所對應T-SQL並可直接試連DB做查詢的工具一枚,十分實用,一併列出供大家參考。

【2009-07-13補充】本草綱目有記載,若要查Query對應的CommandText,可以用DataContext.GetCommand,Insert/Update/Delete的部分則還沒看到Log法的替代方案,如有線報,歡迎提供。

轉自:http://blog.darkthread.net/blogs/darkthreadtw/archive/2009/07/12/linq-to-sql-debugger.aspx