Monday, September 1, 2014

การใช้ C# อ่านฐานข้อมูล MySql แบบเท่ๆ ตอนที่ 3

การใช้ C# อ่านฐานข้อมูล MySql แบบเท่ๆ ตอนที่ 3 (INSERT, UPDATE)


ใน ตอนที่แล้ว เราได้ทำการ SELECT ข้อมูลจากฐานข้อมูลกันได้แล้ว ในครั้งนี้เราจะทำการ INSERT และ UPDATE ฐานข้อมูล โดยใช้เพียงแค่คำสั่งเดียว

เริ่มแรก ให้ทำการเพิ่มโค้ดต่อไปนี้ใน Query.cs เพื่อใช้สำหรับสร้าง sql string เพื่อใช้ในการ update และ insert ข้อมูล ซึ่งเราจะใช้ Reflector อีกแล้ว

Query.cs
        private string Insert(object data)
        {
            //อ่านค่า properties ทั้งหมดใน object ที่รับมา
            PropertyInfo[] props = data.GetType().GetProperties();
            var propNames = new string[props.Length];
            for (int i = 0; i < props.Length; i++)
            {
                propNames[i] = props[i].Name;
            }
            
            //String.Join ทำงานเหมือน implode ใน php คือการเอา string ใน array มาต่อกันโดยใช้ตัวอักษรที่กำหนดมาเชื่อม
            return "INSERT INTO " + _tableName + " (" + String.Join(",", propNames) + ") " + " VALUES (@" + String.Join(",@", propNames) + ")";
        }


        private string Update(object data)
        {
            PropertyInfo[] props = data.GetType().GetProperties();
            var propNames = new string[props.Length];
            for (int i = 0; i < props.Length; i++)
            {
                propNames[i] = props[i].Name;
            }

            string update = "";
            propNames.ToList().ForEach(key => update += key + "=@" + key + ",");
            string prime = GetPrimaryKey(data);
            CutStringRight(ref update, ",");
            return "UPDATE " + _tableName + " SET " + update + " WHERE " + prime + "= @" + prime;
        }
        //ตัดข้อความตั้งแต่อักษรที่กำหนดไปทางขวามือทิ้งทั้งหมด
        private void CutStringRight(ref string str, string cut)
        {
            int length = str.LastIndexOf(cut, StringComparison.Ordinal);
            if (length != -1)
            {
                str = Strings.Trim(str.Substring(0, length));
            }
        }

จากนั้นก็เพิ่ม method IsDuplicate() เข้าไป เพื่อตรวจสอบว่ามีข้อมูลซ้ำหรือไม่

        private bool IsDuplicate(object data)
        {
            string prime = GetPrimaryKey(data);
            foreach (PropertyInfo info in data.GetType().GetProperties())
            {
                if (prime.ToLower() == info.Name.ToLower())
                    prime = info.Name;
            }

            if (data.GetType().GetProperty(prime).GetValue(data, null) == null) 
                return false;

            Where(prime, "=", data.GetType().GetProperty(prime).GetValue(data, null).ToString());
            var list = Get(data.GetType()) as IList;
            return list.Count > 0;
        }

        //ดูว่า field ไหนเป็น Primary key
        public string GetPrimaryKey(object data)
        {
            string sql = "DESCRIBE " + _tableName;
            var command = new MySqlCommand(sql, UniqueDB.Instance.GetConnection());
            MySqlDataReader reader = command.ExecuteReader();
            string prime = "";
            while (reader.Read())
            {
                if (reader["Key"].Equals("PRI"))
                    prime = reader["Field"].ToString();
            }
            reader.Close();
            return prime;
        }

ต่อไปเราจะเพิ่มคำสั่ง Save() เพื่อทำการบันทึกข้อมูลลงฐานข้อมูล
        public void Save(object data)
        {
            string sql;
            if (IsDuplicate(data))
            {
                sql = GetUpdate(data);
            }
            else
            {
                sql = GetInsert(data);
            }
            var command = new MySqlCommand(sql, UniqueDB.Instance.GetConnection());
            PropertyInfo[] props = data.GetType().GetProperties();
            props.ToList().ForEach(
                prop =>command.Parameters.AddWithValue(prop.Name.ToLower(),
                            data.GetType().GetProperty(prop.Name)
                            .GetValue(data, null))
            );
            command.ExecuteNonQuery();
        }

เนื่องจากเราจะเรียกใช้ Query ผ่านคลาส ORM ดังนั้นเราจึงต้องเพิ่มคำสั่ง Save() เข้าไปใน ORM และทำการ overload ให้ไม่ต้องรับค่า parameter อีก

Query.cs
        //สั่งให้ class ลูก save ตัวมันเอง
        public void Save()
        {
             _query.Save(this);   
        }

ลองทดสอบ code ของเราดู
        private static void Main(string[] args)
        {
            UniqueDB.Instance.SetConnection("localhost", "database", "user", "passwd").GetConnection().Open();
            
            Product product = new Product();
            product.Name = "Play Station 5";
            product.Description = "ยังไม่ออก!";
            product.Price = 50;
            product.Save();
            Console.WriteLine("DONE");

            UniqueDB.Instance.GetConnection().Close();
            Console.ReadLine();
        }
เมื่อรันแล้วจะได้การ INSERT record ใหม่
ต่อไปลอง select Wii U มาลดราคาเหลือ 8000 บาทกัน
        private static void Main(string[] args)
        {
            UniqueDB.Instance.SetConnection("localhost", "database", "user", "passwd").GetConnection().Open();
            
            Product product = new Product();
            product.Name = "Wii U";
            product = ((List) product.Find(product))[0];
            product.Price = 8000;
            product.Save();
            Console.WriteLine("DONE");

            UniqueDB.Instance.GetConnection().Close();
            Console.ReadLine();
        }

ได้ผลออกมาดังนี้

ถือว่าสำเร็จไปได้ด้วยดีสำหรับคำสั่ง Save() ของเรา ตอนต่อไปจะเป็นการ Delete ข้อมูลออกจากฐานข้อมูลครับ