ADO.NET #2: The Lightwight Model : Reading Data

    ใน ADO มีความต้องการที่จะรวมศูยน์ทุกอย่างเข้าไปที่ Object Model เดียว แต่เมื่อพิจารณาดูแล้ว ADO.NET เห็นว่าเราควรแยก Model ออกมาเป็นสองส่วน คือส่วนแรกใช้สำหรับ การดึงข้อมูลอย่างง่าย กับการดึงข้อมูลที่ซับซ้อน มีคำถามว่าแล้วทำไมไม่ทำเหมือน ADO คือตัวที่ดึงข้อมูลซับซ้อนได้ ก็ย่อมต้องสามารถดึงอย่างง่ายได้ด้วยจะได้เป็นแบบเดียวกัน ทาง ADO.NET ไขข้อข้องใจนี้ โดยบอกว่า การที่แยก Model ระหว่างการดึงข้อมูลแบบง่ายและแบบซับซ้อนออกจากกันนั้น เพราะในการดึงข้อมูลแบบง่ายที่นิยมใช้กันอยู่ในปัจจุบัน เราต้องเขียน Syntax ที่ซับซ้อนเกินไปเพื่อให้มันรองรับแบบซับซ้อนได้ จึงทำ Model อย่างง่ายเพื่อให้ใช้ง่ายขึ้น และอีกอย่างคือในเมื่อมันเป็น Model ที่เรียบง่ายขึ้น มันจะมีขนาดเล็กลง ทำให้ไม่เปลืองเนื้อที่มาก ในบทนี้เราจะมาเรียนแบบง่ายกันก่อน ในบทต่อไปเราจะมาศึกษา Model ส่วนที่ซับซ้อนกัน

รูปแบบของ Model อย่างง่าย

 

จากรูปเราจะเห็นได้ว่า เวลาเราเขียนโปรแกรมนั้น เราจะยุ่งกับ ADODataReader เป็นหลัก ADODataReader นั้นเป็น Client-Side Cursor ที่มีความสามารถในการทำดึงข้อมูลออกมาได้เพียงอย่างเดียว เขียนข้อมูลกลับไม่ได้ และการดึงข้อมูลนี้ต้องดึงแบบ firehose หรือที่หัวฉีดดับเพลิงเท่านั้น(ADO เรียกว่า Forword Only) ลองนึกดูธรรมชาติของของหัวฉีดดับเพลิง ถ้าเปรียบเทียบว่ามันเป็น ADODataReader และน้ำที่ใช้ฉีดเป็นข้อมูล เมื่อเปิดวาวล์ น้ำก็จะถูกฉีดออก น้ำที่ฉีดออกมานั้นจะเอาคืนกลับก็ไม่ได้ จะเลือกเอาน้ำส่วนที่ต้องการออกก่อนก็ไม่ได้ มันต้องเรียงตามการบรรจุเข้าครั้งแรก อย่างเก่งที่ตัวหัวฉีดก็มีก๊อกเปิดปิดเท่านั้น ADODataReader เป็นเหมือนกับหัวฉีดดับเพลิง ที่เลือกข้อมูลในการดึงไม่ได้ ต้องดึงต่อเนื่องตั้งแต่ต้นจนจบ และเมื่อดึงแล้วจะย้อนเอาข้อมูลเดิมมาดึงอีกทีไม่ได้ แต่เราจะกั๊กข้อมูลยังไม่เอาออก ไปทำงานอย่างอื่นก่อนก็พอทำได้ แต่อย่าทิ้งไว้นานเพราะ ถ้าเราติดต่อกับ Server อยู่มันจะกินทรัพยากรของเครื่อง Server (DataSource)  นานเกินไป การใช้ Model การดึงข้อมูลแบบง่ายนี้ จะต้องต่อเข้ากับ DataSource ตลอดครับเหมือนกับใน ADO

ADODataReader นั้นโดยลำพังคงทำงานไม่ได้ ต้องอาศัย ADOCommand การทำงานของ ADOCommand นั้น จะทำหน้าที่เป็นตัวกลางระหว่าง ADOConnection และ ADODataReader เราสั่งคำสั่ง SQL ไปที่ ADOCommand ซึ่ง ADOCommand จะทำการดึงข้อมูลโดยโดยใช้บริการของ ADOConnection และเมื่อได้ข้อมูลกลับมาก็จะเอามาป้อนเข้า ADODataReader

เรามาลองดู code กันเพื่อความเข้าใจ

ado.cs

using System;
using System.Data.ADO;
class Hello
{ 	
	public static void Main()
	{ 	
		string str;
		str = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\\NorthWind.MDB";
		ADOConnection CN = new ADOConnection(str);
		ADOCommand CMM = new ADOCommand("SELECT * FROM Employees WHERE City='London'", CN);
		
                	ADODataReader DR;
		CN.Open();
		CMM.Execute(out DR);
		while (DR.Read()) {
			Console.WriteLine("{0} {1}", DR["FirstName"], DR["LastName"]);
		}
		DR.Close();
		CMM = null;
		CN.Close();
		CN = null;
			
	}
}

จากโปรแกรมนี้เราใช้ ADOConnection ติดต่อไปยัง Microsoft Access file ซึ่งถ้าคุณเคยใช้ ADO อยู่แล้วคุณคงคุ้นเคยกับ Syntax นี้เป็นอย่างดี ผมคงไม่อธิบายอะไรมาก เชื่อว่าคุณคงอ่าน code ทั้งหมดแล้วเข้าใจได้โดยไม่ยาก

ถ้าคุณสังเกตที่รูปข้างบน คุณอาจเห็นว่าชั้นสุดท้ายก่อนถึง Data Source นั้นมันต้องผ่าน OLEDB ก่อน แบบนี้มีปัญหาแน่ครับ คือ OLEDB นั้นเป็น COM Component ไม่ใช่ .NET ดังนั้นมันจึงเกิดการแปลงที่เรียกว่า InterOp จาก .NET ไปเป็น COM ซึ่งมันทำให้ช้ามาก แล้วทำไม .NET ถึงทำเช่นนี้?

เรื่องของเรื่องคือทำไม่ทันครับ ADO.NET มีความตั้งใจอย่างสูงจะยกเลิก OLEDB แต่ก็ทำไม่ทัน Microsoft ยกเลิกแนวคิดที่ว่า ตัว Connection นั้นตัวเดียวครอบจักรวาล ซึ่งถ้าทำอย่างนั้นเหมือนกับ ADO จะทำให้ประสิทธิภาพเสียเพราะต้องทำให้ใช้ได้กับทุกๆ DBMS ทาง ADO.NET จึงใช้หลักการว่า 1  Connection Class ต่อหนึ่งชนิด DBMS จะได้เร่งประสิทธิภาพกันได้เต็มที่ ซึ่งในขณะนี้ Microsoft ทำเสร็จเพียง SQLConnection ที่เอาไว้ต่อกับ Microsoft SQL Server เท่านั้น SQLConnection นั้นติดต่อกับ Microsoft SQL Server โดยตรงโดยไม่ผ่าน OLEDB จึงทำงานได้เร็วกว่า  ส่วน OracleConnection หรืออื่นๆ ยังทำไม่เสร็จ จึงจำเป็นต้องต่อกับ OLEDB โดยใช้ ADOConnection ในอนาคตอันใกล้เราคงได้เห็น Connection เฉพาะสำหรับ DBMS ต่างๆ

เรามาลองดู Code ที่เป็น SQLConnection ดีกว่า

sql.cs

using System;
using System.Data.SQL;
class Hello
{ 	
	public static void Main()
	{ 	
		SQLConnection CN = new SQLConnection("Server1", "sa", "", "northwind");
		SQLCommand CMM = new ADOCommand("SELECT * FROM Employees WHERE City='London'", CN);
		
                	SQLDataReader DR;
		CN.Open();
		CMM.Execute(out DR);
		while (DR.Read()) {
			Console.WriteLine("{0} {1}", DR["FirstName"], DR["LastName"]);
		}
		DR.Close();
		CMM = null;
		CN.Close();
		CN = null;
			
	}
}

จาก Code นี้จะเห็นได้ว่า เราต้องเปลี่ยนเป็น SQLConnection, SQLCommand, SQLDataReader เปลี่ยนยกชุด

ในบทต่อไปผมจะพูดถึงการเขียนข้อมูลกลับเข้า DBMS