iT邦幫忙

0

C#呼叫TSQL相關問題

最近剛學程式,我要到一個程式碼,目前只能大略看出一些輪廓,可是還是不太懂,
希望各為能幫我解答一下,執行結果應該會有500筆資料

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication2
{
    class Program
    {
        
        public class Seat {
            public DateTime ptime { get; set; }
            public int Movie { get; set; }
            public string Seat_Num { get; set; }
            public int soldd { get; set; } //1 表 售出, 0 表未售出
            //流水號不用
        }
        static void Main(string[] args)
        {
            List<Seat> SeatList = new List<Seat>();
            for (int i = 0; i <= 500; i++) //產生500筆資料
            {
                SeatList.Add((new Seat
                {
                    ptime = DateTime.Now.AddDays(i),
                    Movie = i+100,
                    Seat_Num =i.ToString(),
                    soldd = 0
                }));
            }       
            string ConnString = "Data Source=127.0.1;Initial Catalog=Sample666;Integrated Security=True";
            SqlConnection conn = new SqlConnection(ConnString);
            DataTable dt = new DataTable();
            SqlCommand cmd = null;
            try
            {
                dt.Columns.Add("ptime", typeof(DateTime));
                dt.Columns.Add("movie", typeof(int));
                dt.Columns.Add("seat_num", typeof(string));
                dt.Columns.Add("sold", typeof(int));
                
                for (int i = 0; i < SeatList.Count; i++)
                {
                    DataRow dr = dt.NewRow();
                    //如果有空值會死掉
                    dr["ptime"] = SeatList[i].ptime;
                    dr["movie"] = SeatList[i].Movie;
                    dr["seat_num"] = SeatList[i].Seat_Num;
                    dr["sold"] = SeatList[i].soldd;
                    dt.Rows.Add(dr);
                }
                conn.Open();
                using (SqlBulkCopy sqlBC = new SqlBulkCopy(conn))
                {
                    sqlBC.ColumnMappings.Add("ptime", "ptime");
                    sqlBC.ColumnMappings.Add("movie", "movie");
                    sqlBC.ColumnMappings.Add("seat_num", "seat_num");
                    sqlBC.ColumnMappings.Add("sold", "sold");
                    sqlBC.BatchSize = SeatList.Count;
                    sqlBC.BulkCopyTimeout = 60;
                    sqlBC.DestinationTableName = "[seats]";
                    sqlBC.WriteToServer(dt);
                }
            }
            catch (Exception ex)
            {
             
            }
            finally
            {
                conn.Dispose();
            }

        }
    }
}

第一個for回圈我知道是產生500筆資料,可是第2個for回圈的用意是什麼?我只知道
說他是空值就會error,但還是不太清楚這迴圈的用意,希望能為我講解一下,謝謝。

4
神Q超人
iT邦新手 1 級 ‧ 2018-06-01 19:20:01
最佳解答

HI!我針對第二個迴圈講解一下,
如果有不懂的可以在留言提問!

//這個迴圈是在跑第一個迴圈放進SeatList的五百筆資料
for (int i = 0; i < SeatList.Count; i++)
{
    //宣告一個DataRow,這個是一個資料行的物件
    DataRow dr = dt.NewRow();
    //(1)如果有空值會死掉(這邊以下再解釋)
    //以下四行做設定,設定該行各欄位(dr["ptime"])的欄位值(SeatList[i].ptime)
    dr["ptime"] = SeatList[i].ptime;
    dr["movie"] = SeatList[i].Movie;
    dr["seat_num"] = SeatList[i].Seat_Num;
    dr["sold"] = SeatList[i].soldd;
    //(2)之後把該行加進dt
    dt.Rows.Add(dr);
}

所以上面那個迴圈的過程就是把第一個迴圈放進SeatList的資料再放進dt中。這時候你可能會出現兩個問號,第一個是標註(1)的地方「為什麼有空值的話會出錯?」再解釋這個前我們先來看看dt怎麼來的:

/*再稍微上方一點的地方,我們宣告了一個資料表的物件dt,
所以我們也才能把剛剛產生出來的欄位放進來。*/
DataTable dt = new DataTable();

接著我們從剛剛宣告dt那一行往下看一下,會有這麼一段:

//這一段主要是在為該資料表增加欄位,並設定該欄位的型態。
//例如日期時間、數字、字串等...
dt.Columns.Add("ptime", typeof(DateTime));
dt.Columns.Add("movie", typeof(int));
dt.Columns.Add("seat_num", typeof(string));
dt.Columns.Add("sold", typeof(int));

好的,那接下來可以說說什麼在標註(1)的地方空值為什麼會出錯,是因為放進去的值不符合該欄位設定的屬性,所以他就會因為錯誤而被捕捉到,跑到catch中,執行出錯後的程式碼,但目前catch內的程式碼是空的,所以就沒有執行錯誤處理。

看更多先前的回應...收起先前的回應...
tenno081 iT邦新手 4 級 ‧ 2018-06-01 20:56:09 檢舉

太感謝您的解答了,我想再請問就是第一段的部分,我知道他是
自動實作的屬性,但我不太清楚何時會用到這功能,我只知道這樣是讓我
在裡面宣告的東西設定成唯讀跟唯寫,在來是BulkCopyTimeou=60
這個語法,官方是說如果作業逾時,不會認可交易和目的地資料表中移除所有複製的資料列。那意思是說我這程式執行超過60秒就刪除掉剛剛所複製到的資料嗎?那因為我這支成是所要執行的資料較少,所已其實不用這行應該也可以嗎?

第一段是指List那部分嗎?那是一個物件導向的概念,先宣告一個class物件存放你說的唯讀和唯寫的變數,之後在以下程式碼去new出那個物件(1),並指定欄位資料放進List(2)

List<Seat> SeatList = new List<Seat>();
for (int i = 0; i <= 500; i++) //產生500筆資料
{
    SeatList.Add((new Seat{           //(1)把物件給new出來
    ptime = DateTime.Now.AddDays(i),  //(2)設定new出來的物件中的值
    Movie = i+100,                    //(2)
    Seat_Num =i.ToString(),           //(2)
    soldd = 0}));                     //(2)
}   

而那句BulkCopyTimeout=60也像你說的哦!回復交易的意思就是先前做更動的都不會被承認,如果目前的資料跑的完,就可以不用去設定,但是如果不去設定BulkCopyTimeout的話預設值是30秒ㄛ!這個要注意一下!/images/emoticon/emoticon13.gif

tenno081 iT邦新手 4 級 ‧ 2018-06-02 14:42:17 檢舉
public class Seat {
            public DateTime ptime { get; set; }
            public int Movie { get; set; }
            public string Seat_Num { get; set; }
            public int soldd { get; set; } //1 表 售出, 0 表未售出
            //流水號不用
        }

我是對這段比較好奇,因為我目前大部分都是類似int i = 1;這樣,
還沒有設定說唯讀唯寫這樣,我比較想知道,什麼時候需要為他設定
唯讀唯寫這樣?不然我可能只會單純的設定說 DateTime ptime=XXX
int movie=XXX之類的

那是因為目前程式碼的需求比較簡單,以後如果在還沒放資料前需要預設值(get),或是在設定(set)該值的時候需要為他做些處理,就可以用這兩個屬性做處理。
不好意思!因為現在人在外面,等晚上我再補上程式碼解釋!

這個是存取器的應用,可以讓讀寫的時候變得更有彈性,也能像以下程式碼再取值或設值的時候加一些判斷程式碼,然後因為我舉例滿爛的/images/emoticon/emoticon16.gif,所以程式碼有問題可以再提出:D

public class people  //做一個人物的class
        {
            public string name;          //在class裡宣告一個姓名字串
            public string nameAccessors  //做一個字串的存取器
            {
                get //取值時
                {
                    if(name == null || name == "")  //如果name是null或是空的就回傳"未輸入姓名"
                    {
                        return "未輸入姓名!";
                    }
                    else  //否則就回傳姓名的值
                    {
                        return name;
                    }
                }
                set //設值時
                {
                    //這個value是設值時會自動填入的變數名稱,他的值會傳入你要設定的值。
                    if (value == "")   //這邊判斷如果value等於空的話再寫進去name裡面
                    {
                        name = value;  //把value的值給name
                    }
                    else if(name == null || name == "") //如果value不等於空的話,就判斷name等於null或空就把value的值給name
                    {
                        name = value;
                    }
                }
            }

        }

        static void main()
        {
            //用來放目前的name值
            string peopleName;
            /*這個存取器的設定會是如下:
            get:取name時,如果name的值為空的或是null會預設回傳"未輸入姓名!"
            set:設定name時,必須先將原本的name值指定為空才可重新設值*/

            //初始化時去呼叫存取器取值,
            //peopleName會是"未輸入姓名!"
            people Rex = new people();
            peopleName = Rex.nameAccessors;

            //設定值為"Rex",進入set後value會等於"Rex",所以value不等於空,name這時候也還沒有值,
            //peopleName會是"Rex"
            Rex.nameAccessors = "Rex";
            peopleName = Rex.nameAccessors;

            //設定值為"Json",進入set後value會等於"Json",所以value不等於空,但name這時候是"Rex,所以"Json"就不會寫入,
            //peopleName會是"Rex"
            Rex.nameAccessors = "Json";
            peopleName = Rex.nameAccessors;

            //這裡設定值為"",進入set後value會等於"",所以value等於空,name就會寫入"",
            //peopleName會是""
            Rex.nameAccessors = "";
            peopleName = Rex.nameAccessors;

            //設定值為"Json",進入set後value會等於"Json",所以value不等於空,name這時後又是空的,所以"Json"就會寫入,
            //peopleName會是"Json"
            Rex.nameAccessors = "Json";
            peopleName = Rex.nameAccessors;
        }
tenno081 iT邦新手 4 級 ‧ 2018-06-03 20:26:30 檢舉

太感謝您的解答了,這讓我學到不少

0
小魚
iT邦大師 1 級 ‧ 2018-06-01 19:13:01

我倒是沒這樣用過,
第二個for迴圈是將資料塞到DataTable裡面,
至於 空值就會error,
我覺得應該是Null會error吧,
把Null處理掉就好了。

0
danking
iT邦研究生 2 級 ‧ 2018-06-04 00:00:19

第一個迴圈,產生500筆資料並塞入到 SeatList 裡面
第二個迴圈,將SeatList的資料塞入到 DataTable 中

為什麼空值會死掉,是因為 DateTime/int 不允許空值
請查看 Exception 的訊息內容,就可以知道是哪一個欄位造成的錯誤囉

我要發表回答

立即登入回答