網頁

2012年10月26日 星期五

結訓了 面對社會吧

結訓了,畢業啦,學到了非常大量的知識,也將這堆知識整理成自己與別人都看的懂的網站,總算可以很自信的告訴別人,我會什麼。

講到這三個月,真的很難講完,學到太多東西了,我們不只要會程式,還要會美工,最好還要會設計版型,再加上雲端應用,不為什麼,因為老闆是個變態的生物阿!(蔡老師名言XD,當然老師們也不算XD


也因為如此,我必須說-作一個網站並不容易,一個網站如果沒人看得懂流程或是動線,那就不算成功的網站,並且不要邊作邊改!這樣不僅容易打亂時程,也容易造成不可預期的意外!(改了就出錯 跑一跑自動出錯......
所有事情都是需要規劃才能完美呈現......



另外,資料庫是非常重要的一環,現在之所以還沒法體會到是因為資料量太少了,資料量一多就可以明顯看出來差異。SQL要學好,任何人都會CRUD,但是如何有效存取真的是一門大學問,我也準備朝這行業進行,目標是攻略各家資料庫@@。
資料庫真的很好玩,玩下去就離不開了(?

最後 謝謝老師們的指導。我會繼續努力的!
接下來就是不斷的尋找,那心有靈犀的公司......

2012年10月20日 星期六

以Commandname或CommandArgument參數切換頁面


 筆者在做一個網頁時,由於該網頁的按鈕不少(6-8個),每個按鈕都是轉向至指定網址,因此想要透過一些偷吃步來精簡程式碼XD,首先想到的就是使用switch來判斷按鈕傳回的參數.

注意Page_Load中的事件

筆者最近在測試一些DB資料型別時,遇到一個問題,程式碼如下:

2012年10月12日 星期五

以ViewState暫存資料

筆者最近在寫網站的購物車結帳流程,寫的時候為了方便消費者了解目前買了哪些產品,以及產品的單價與總金額,由於總金額 = 每個產品的數量 * 每個產品的單價,
筆者在購物清單中加了一個下拉式選單選擇數量,並從GridView中抓產品的單價,不過做的時候發現有個問題:
數量選擇9個時*產品單價200 = 總金額1800元,用來暫存總金額的Label的確是1800元結帳時拿Label的1800存到資料表中的total
結帳完畢後卻發現資料表中的total還是數量1*單價200 = 總金額200元!!!
怎麼會這樣呢? 筆者請教老師後才知道,原因是因為下拉式選單更新數量後頁面會重新載入,所以Label中的1800自然而然就歸零了!要先將總金額1800元存到暫存區內再轉送到資料表而解決方法就是先將資料存到ViewState中,如此一來畫面即使重新整理後總金額並不會被歸零。

ViewState的用法如下:
存資料至State-
ViewState[0] = "123";

讀取ViewState[0]的資料放置 x-
string x = Convert.ToString(ViewState[0]);

當然,ViewState可以存放整數或其他的資料型別,也可以自訂索引的名稱。
如:
int i = 500;
ViewState["total"] = total;

int y = Convert.ToInt32(ViewState["total"].ToString());
or
int y =  int.Parse(ViewState["total"].ToString());

但要注意的是,ViewState只會在該頁面中暫存,一旦離開後ViewState就會自動清除了。

2012年10月9日 星期二

使用CommandArgument傳遞多個參數

筆者寫網頁常需要在GridView中加入Button控制項,做為輸入資料的依據。
通常觸發Button_Click後需要傳遞GridView中一些資料作為輸入的資料來源,
之前筆者是使用如下面程式碼的方式抓取GridView中的Label或TextBox的文字以便輸入資料:
--為方便比較筆者將Button的屬性一並放上
--aspx檔部分
<asp:Button ID="Button1" runat="server" CommandName="ShopCar" Text="Button"  />

--cs檔部分
 Label booksid = (Label)DataList1.Items[e.Item.ItemIndex].FindControl("booksidLabel");
 Label booksname = (Label)DataList1.Items[e.Item.ItemIndex].FindControl("booksnameLabel");
 Label booksprice = (Label)DataList1.Items[e.Item.ItemIndex].FindControl("bookspriceLabel");

這種作法最大的缺點每抓取一筆資料就需要宣告一個Label或TextBox物件
程式無法撰寫的太精簡,因為需要這些屬性。
後來筆者參考這個網址的做法:以CommandArgument傳遞多個參數

將程式碼改為CommandArgument傳遞所需的參數,如此一來不需要知道Label的ID也能傳遞參數。

--aspx檔部分
<asp:Button ID="Button1" runat="server" CommandName="ShopCar" Text="Button" 
   CommandArgument='<%# Eval("booksid")+","+ Eval("booksname")+","+Eval("booksprice") %>' />

--cs檔部分則改為
string booksid = e.CommandArgument.ToString().Split(',')[0].Trim();
string booksname = e.CommandArgument.ToString().Split(',')[1].Trim() ;
string booksprice = e.CommandArgument.ToString().Split(',')[2].Trim();


以這個程式碼為例,筆者要傳遞三個參數,筆者不需要知道三個Label的ID就能直接抓取與booksid  booksname booksprice繫結的欄位並將資料傳遞至cs檔中暫存。
對於常常搞混Label ID的筆者而言的確比較方便,也不會因為更動GridView繫結的物件造成資料錯誤。

2012年10月6日 星期六

使用ADO.NET實體模型與Linq to Entities實作購物車結帳流程


string id = Session["membersid"].ToString();
        using (bookstoreEntities1 orderins = new bookstoreEntities1())
        {
            order ins = new order();
            ins.membersid = id;
            ins.ordertotal = int.Parse(Label3.Text);
            ins.addressee = TextBox5.Text;
            ins.phone = TextBox4.Text;
            ins.address = TextBox3.Text;
            ins.situationid = 1;
            orderins.AddToorder(ins);
            orderins.SaveChanges();
            //查詢最新一筆訂單
            int orderid = 0;
            var o_id = (from p in orderins.order
                        where p.membersid == id
                        orderby p.orderdate descending
                        select p).First();
            if (o_id.ToString() != null)
            {
                orderid = int.Parse(o_id.orderid.ToString());
            }
            //查shopcar資料準備寫入orderlist
            var s_data = (from p in orderins.shopcar
                          where p.membersid == id
                          select p).ToList();
            //抓shopcar數量與書籍編號 放入q bkid
            int q = 0;
            int bkid = 0;
            if (s_data.Count > 0)
            {
                for (int i = 0; i < s_data.Count; i++)
                {
                    orderlist listins = new orderlist();
                    DropDownList quan = (DropDownList)GridView1.Rows[i].Cells[3].FindControl("DropDownList1");
                    Label booksid = (Label)GridView1.Rows[i].Cells[0].FindControl("Label2");
                    q = int.Parse(quan.SelectedValue);
                    bkid = int.Parse(booksid.Text);
                    listins.orderid = orderid;
                    listins.booksid = bkid;
                    listins.quantity = q;
                    orderins.AddToorderlist(listins);
                }
                //刪除購物車中該會員資料
                var s_del = from p in orderins.shopcar
                            where p.membersid == id
                            select p;
                foreach (var x in s_del)
                {
                    orderins.DeleteObject(x);
                }
                orderins.SaveChanges();
            }
        }

2012年10月5日 星期五

MySQL遠端存取


一般初學者可能以為MySQL是免費軟體
所以 =效能比較差 或是管理介面一定不好用 .....等等
但其實以筆者近兩個月的使用經驗來說
MySQL是一套實用且易學的資料庫系統
使用者僅需具備基本的英文能力即可輕鬆上手

同時MySQL可以執行於大多數的網頁語言
MySQL原廠即提供 PHP .NET JAVA C C++ Python 等網頁語言的橋接元件(Connection Provider)
只要將橋接元件安裝完成後打開Visual Studio將橋接元件加入參考後就能使用如SqlClient語法的Intellsense
近期更提供套裝的安裝程式 安裝資料庫的同時也將橋接元件一併安裝至妳的電腦
因此筆者認為MySQL是一套容易且效能不錯的資料庫軟體

但MySQL由於安全性的考量
在遠端存取資料庫時不可使用預設的root帳號存取資料
也就是說 網頁並非在本地端執行欲使用root進行資料庫連線時
MySQL會拒絕其root帳號的存取動作
因此須以其他帳號與資料庫連線存取資料

註: MySQL也是有普通版(MySQL Community Server) 商業版(MySQL Enterprise Edition) 與 叢集版(MySQL Cluster)的分別
不知道為什麼大家都會認為MySQL就是免錢的軟體 = =
MySQL官方網站:http://www.mysql.com/
MySQL資料庫系統與橋接元件下載: http://www.mysql.com/downloads/
MySQL資料庫管理系統:http://www.mysql.com/downloads/workbench/

2012年10月2日 星期二

使用LINQ to Entities語法須注意轉型問題


筆者這兩天將以前使用ADO.NET寫的SQL語法改為LINQ to Entities語法時發現
不管是查詢或是新增資料時 
如果需要文字方塊輸入資料後轉換資料型別
必須事先將轉型後的資料存為int 或 string  or... etc.
否則會跳出錯誤......

假設筆者欲作一個查詢語法如下:
var sel = from p in 購書資料庫.購物車資料表
              where p.會員ID == memberid.Text && p.書籍ID == int.Parse(booksid.Text)
              select p;

則系統會跳出:
"LINQ to Entities 無法辨識方法 'Int32 Parse(System.String)' 方法,而且這個方法無法轉譯成存放區運算式。"

因此需事先將欲輸入的資料轉為對應的資料型別後,再進行查詢。
正確的語法如下:
int bkid = int.Parse(booksid.Text);

var sel = from p in 購書資料庫.購物車資料表
              where p.會員ID == memberid.Text && p.書籍ID == bkid
              select p;

注:補充一點,如要將資料轉為整數(int)時,可以用int.Parse() 或者是Convert.ToInt32()來實作

2012年10月1日 星期一

以SqlTransaction搭配具名參數實作轉帳流程

一般而言,,簡略的轉帳流程大致可分為幾個部分:
1. 查詢帳戶餘額是否大於要轉帳的金額,如餘額足夠付款則進行下一個動作。
2. 轉出付款者所輸入的金額至收款者帳戶,付款者帳戶餘額 = 原始餘額扣除轉出金額。
3. 轉入付款者所輸入的金額至收款者帳戶,收款者帳戶餘額 = 原始餘額加上轉入金額。
4. 如上述動作皆完成,則通知付款者轉帳成功;
如未成功則不更動收(付)款者帳戶餘額,並通知付款者轉帳失敗。

簡而言之,即是將付款者帳戶餘額扣掉輸入之金額後再將收款者帳戶餘額加上輸入之金額。

而要如何利用SqlTransaction來做出轉帳功能呢?
其實很簡單,照著上述流程走就行了!
只是筆者建議作新增、修改、刪除皆使用具名參數輸入資料,以確保安全。

轉帳流程範例程式碼如下:


using.System.Data.SqlClient;//引用SqlClient以進行轉帳
using System.Data;//引用Data以進行餘額查詢
.
. 
.
.
//----------------------Button1_Click
 //宣告使用的物件
        SqlConnection connect = new SqlConnection
            ("server = localhost; uid = xxxx; pwd = xxxx; database = transaction;");
        SqlDataReader dr;
        //inquirecmd為查詢餘額,transoutcmd為轉帳出戶金額, transincmd為轉帳入戶金額;
        SqlCommand inquirecmd,transoutcmd, transincmd;
         //開啟連線

        connect.Open();
        //宣告交易物件並開始資料庫交易
        SqlTransaction tran = connect.BeginTransaction();
        try
        {
            
            //執行餘額查詢,並限制付款方帳戶餘額須大於轉出金額才可進行轉帳
            inquirecmd = new SqlCommand
            ("SELECT @payuser FROM account WHERE user = @payuser AND balance >= @money",
 connect);
            //定義餘額查詢中具名參數及給值
            inquirecmd.Parameters.Add("@payuser", SqlDbType.NVarChar).Value = payuserBox.Text;
            inquirecmd.Parameters.Add("@money", SqlDbType.NVarChar).Value = int.Parse(moneyBox.Text);
            inquirecmd.ExecuteNonQuery();
            //將查詢結果帶入dr
            dr = inquirecmd.ExecuteReader();
            //假如餘額大於轉出金額則進行轉帳,小於轉出金額則中斷轉帳流程並提醒使用者餘額不足
            if (dr.Read())
            {
                 dr.Close();
                //扣除付款方餘額,請注意connect後方加入了tran,表示此指令列為轉帳流程之一
                transoutcmd = new SqlCommand
                    ("UPDATE account SET balance = balance - @money WHERE user = @payuser", connect,
 tran);
                //增加付款方餘額,請注意connect後方加入了tran,表示此指令列為轉帳流程之一
                transincmd = new SqlCommand
                    ("UPDATE account SET balance = balance + @money WHERE user = @getuser", connect, 
tran);
                //定義付款方扣款指令中具名參數及給值
                transoutcmd.Parameters.Add("@money", SqlDbType.Int).Value = int.Parse(moneyBox.Text);
                transoutcmd.Parameters.Add("@payuser", SqlDbType.NVarChar).Value = payuserBox.Text;
                //定義收款方指令中具名參數及給值
                transincmd.Parameters.Add("@money", SqlDbType.Int).Value = int.Parse(moneyBox.Text);
                transincmd.Parameters.Add("@getuser", SqlDbType.NVarChar).Value = getuserBox.Text;
                //執行轉帳流程,如轉出與轉入流程皆完成則交易成功
                transoutcmd.ExecuteNonQuery();
                transincmd.ExecuteNonQuery();
                //交易成功,顯式交易成功訊息及交易金額
                tran.Commit();
                Response.Write("交易成功,交易金額為" + moneyBox.Text);
            }
            else
            {
                //查詢結果餘額不足,提醒消費者並且不進行轉帳流程
                throw new Exception("餘額不足");
            }
        }
        catch (Exception ex)
        {
            //交易失敗,將交易資料復原至交易開始時,並通知使用者交易失敗
            tran.Rollback();
            Response.Write("交易失敗,請確認輸入之帳戶是否正確");
        }

            connect.Close();