Tuesday, November 09, 2010

LẬP TRÌNH ORACLE VỚI ODP.NET [C#]

Bài viết dành cho các lập trình viên làm quen với việc lập trình cơ sở dữ liệu Oracle trên nền .NET.

“CHAT”

Sẽ có người hỏi sao lại lập trình Oracle với .NET nhỉ, thường thì nghe người ta nói với Oracle là phải Java, chẳng phải Oracle được phát triển bằng Java đó sao.

Bây giờ chúng ta coi như Oracle là quần jean, Java là áo bun (áo phong) còn .NET là áo sơ mi. Thường thì người ta mặc quần jean với áo bun, nhưng có một số trường hợp có thể mặc quần jean với áo sơ mi, đó có thể là:

Mặc quần jean với áo sơ mi mà nhìn vấn đẹp, có khi đẹp hơn ấy chứ.

Dạo này thấy người ta mặc quần jean với áo sơ mi nhiều nhỉ, phải theo thời trang chứ.

Và quan trọng là ở chỗ đó người ta chỉ cho phép mặc áo sơ mi!

Tốt nhất là không nên mất nhiều thời gian vào chuyện đó, cứ thấy phù hợp nhất đối với công việc của mình là được. Sau này có thời gian mình sẽ viết một bài về Web service + Java + Linux + Oracle, hoặc là những tips nhỏ sử dụng những đoạn chương trình Java ngay trong Oracle. Còn bây giờ nếu bạn quan tâm thì chúng ta bắt đầu. Mà để có thể bắt đầu được thì các bạn phải cài đặt Oracle Server, Oracle Client, .NET framework và viết thành công một chương trình nhỏ kết nối thành công tới Oracle. Về phần này mình không trình bày trong bài viết nên các bạn có thể tự tìm hiểu.

CÁC KIẾN THỨC CƠ BẢN

.NET

Đọc là “đốt nét”.

Hệ quản trị cơ sở dữ liệu Oracle

Điều cần nhắc tới ở đây đó là phiên bản đầu tiên của Oracle là Oracle 2. Điều này xem ra thật thú vị và đó cũng là một trong những kinh nghiệm hay về giới thiệu và quảng bá sản phẩm.

Cursor, Function, Procedure, Packet …

Là những khái niệm thường thấy trong bài viết này

Cursor: con trỏ, dùng lưu kết quả của câu lệnh select.

Ví dụ:

Cursor my_cursor is select * from ITS where 1 = 1;

Function: hàm, thực thi những tác vụ gì đó và trả về kết quả.

CREATE [OR REPLACE] FUNCTION [ (parameter [,parameter]) ]

RETURN
IS|AS

[declaration_section]
BEGIN

statements;

RETURN return_value;

[EXCEPTION

WHEN exception_name THEN

statements;]
END[function_name];

Ví dụ:

FUNCTION ITS_FUN (param1 IN VARCHAR2)

RETURN VARCHAR2

IS

BEGIN

RETURN param1;

END its_fun;

Procedure: gom các câu lệnh cần thực thi như select, update, insert, delete lại một chỗ và biên dịch một lần. Có tên gọi đầy đủ là store procedure hay còn thường được gọi là SP.

CREATE [OR REPLACE] PROCEDURE procedure_name

[ (parameter [,parameter]) ]

IS

[declaration_section]

BEGIN

executable_section

[EXCEPTION

exception_section]

END [procedure_name];

Ví dụ:

PROCEDURE its_proc (v_its_worktime IN NUMBER)

IS

BEGIN

UPDATE its

SET worktime = 0

WHERE worktime > v_its_worktime;

DELETE its

WHERE worktime > v_its_worktime;

END;

Package: gom các cursor,function, procedure … liên quan lại với nhau, đi kèm với package là package body – cài đặt chi tiết cho các SP và functions đã khai báo trong package.

Ví dụ: (Một package trong bài viết)

PACKAGE PAC_TABLE4

IS

-- Person Date Comments

-- ITS 08/10/2008

TYPE t_cursor IS REF CURSOR;

TYPE array_id IS TABLE OF NUMBER

INDEX BY PLS_INTEGER;

TYPE array_name IS TABLE OF VARCHAR (100)

INDEX BY PLS_INTEGER;

TYPE array_address IS TABLE OF VARCHAR (200)

INDEX BY PLS_INTEGER;

TYPE array_phone IS TABLE OF VARCHAR (25)

INDEX BY PLS_INTEGER;

PROCEDURE insert_data_asso (

p_name IN array_name,

p_address IN array_address,

p_phone IN array_phone

);

PROCEDURE update_data_asso (

p_id IN array_id,

p_name IN array_name,

p_address IN array_address,

p_phone IN array_phone

);

PROCEDURE delete_data_asso (p_id IN array_id);

PROCEDURE select_data (o_cursor OUT t_cursor);

END pac_table4;


ODP.NET

Tên tiếng anh

Một gói thư viện của Oracle dành cho lập trình Oracle với .NET, xem thêm tại link:

http://www.oracle.com/technetwork/topics/dotnet/whatsnew/index.html

Có một điểm lưu ý nhỏ là nếu như trong máy bạn đã cài đặt Oracle Client thì sau khi bạn cài đặt ODP.NET vào sau thì path sẽ ưu tiên thư mục bin của ODP.NET. Bạn vào start-run-cmd-path, sẽ thấy liệt kê path hiện thời của windows. Bạn có thể hiệu chỉnh thứ tự của path bằng cách vào My Computer-Properties-Advanced-Environment Variables – System variables – Path – Edit. Và nếu chọn path đầu tiên trỏ tới bin của Oracle Client hay bin của ODP.NET thì cũng phải tạo TNS tương ứng trong thu mục network-admin. Nếu không bạn sẽ gặp phải lỗi:

ORA-12154: TNS:could not resolve service name

TẠO MỘT PROJECT .NET

Bạn muốn dùng lại project có sẳn trong thư mục sourcecode đi kèm thì máy bạn phải cài đặt .NET framework 3.5 và dùng Visual Studio 2008.

Để sử dụng ODP.NET thì bạn phải Add Preference gói thư viện này vào. Như hình dưới đây thêm vào thư viện ODP.NET Oracle 9.2.


đây chỉ là một ứng dụng demo nên mình fix code luôn chuổi connectionString. Và TNS của mình là :

ITS_DB =

(DESCRIPTION =

(ADDRESS_LIST =

(ADDRESS = (PROTOCOL = TCP)(HOST = ITS)(PORT = 1521))

)

(CONNECT_DATA =

(SERVER = DEDICATED)

(SERVICE_NAME = ITS_DB)

)

)

và username và password login vào database của mình là:

Username: ITS, Password: its123456

Nên mình fix code:

private string connectionString = "Data Source=ITS_DB;User Id=ITS;Password=abc123456;";

(Chỉnh sửa tại file FormMain.cs line: 9, nhấn Ctrl+G và nhập số line để đến line cần tìm)

TRIỂN KHAI DATABASE

Bước 1: Tạo user để thử nghiệm chương trình. Ví dụ như mình tạo user: ITS, password: abc123456

Bước 2: Tạo table1, table1_seq

CREATE TABLE table1

(ID NUMBER(12,0),

NAME VARCHAR2(100),

address VARCHAR2(200),

phone VARCHAR2(25))

PCTFREE 10

INITRANS 1

MAXTRANS 255

TABLESPACE users

STORAGE (

INITIAL 65536

MINEXTENTS 1

MAXEXTENTS 2147483645

)

NOCACHE

NOMONITORING

CREATE SEQUENCE table1_seq

INCREMENT BY 1

START WITH 1

MINVALUE 1

MAXVALUE 999999999999999999999999999

NOCYCLE

NOORDER

CACHE 20

Bước 3: Tạo table2, table2_seq, pac_table2 (bao gồm body)

CREATE TABLE table2

(ID NUMBER(12,0),

NAME VARCHAR2(100),

address VARCHAR2(200),

phone VARCHAR2(25))

PCTFREE 10

INITRANS 1

MAXTRANS 255

TABLESPACE users

STORAGE (

INITIAL 65536

MINEXTENTS 1

MAXEXTENTS 2147483645

)

NOCACHE

NOMONITORING

CREATE SEQUENCE table2_seq

INCREMENT BY 1

START WITH 1

MINVALUE 1

MAXVALUE 999999999999999999999999999

NOCYCLE

NOORDER

CACHE 20

CREATE OR REPLACE

PACKAGE pac_table2

IS

-- Person Date Comments

-- ITS 08/10/2008

TYPE t_cursor IS REF CURSOR;

PROCEDURE insert_data (

p_name IN VARCHAR2,

p_address IN VARCHAR2,

p_phone IN VARCHAR2

);

PROCEDURE update_data (

p_id IN NUMBER,

p_name IN VARCHAR2,

p_address IN VARCHAR2,

p_phone IN VARCHAR2

);

PROCEDURE delete_data (p_id IN NUMBER);

PROCEDURE select_data (o_cursor OUT t_cursor);

END;

CREATE OR REPLACE

PACKAGE BODY pac_table2

IS

-- Person Date Comments

-- ITS 08/10/2008

PROCEDURE insert_data (

p_name IN VARCHAR2,

p_address IN VARCHAR2,

p_phone IN VARCHAR2

)

IS

BEGIN

INSERT INTO table2

(ID, NAME, address, phone

)

VALUES (table2_seq.NEXTVAL, p_name, p_address, p_phone

);

END;

PROCEDURE update_data (

p_id IN NUMBER,

p_name IN VARCHAR2,

p_address IN VARCHAR2,

p_phone IN VARCHAR2

)

IS

BEGIN

UPDATE table2

SET NAME = p_name,

address = p_address,

phone = p_phone

WHERE ID = p_id;

END;

PROCEDURE delete_data (p_id IN NUMBER)

IS

BEGIN

DELETE table2

WHERE ID = p_id;

END;

PROCEDURE select_data (o_cursor OUT t_cursor)

IS

BEGIN

OPEN o_cursor FOR

SELECT ID, NAME, address, phone

FROM table2;

END;

END;

Bước 4: Tạo table3, table3_seq, pac_table3 (bao gồm body)

CREATE TABLE table3

(ID NUMBER(12,0),

NAME VARCHAR2(100),

address VARCHAR2(200),

phone VARCHAR2(25))

PCTFREE 10

INITRANS 1

MAXTRANS 255

TABLESPACE users

STORAGE (

INITIAL 65536

MINEXTENTS 1

MAXEXTENTS 2147483645

)

NOCACHE

NOMONITORING

CREATE SEQUENCE table3_seq

INCREMENT BY 1

START WITH 1

MINVALUE 1

MAXVALUE 999999999999999999999999999

NOCYCLE

NOORDER

CACHE 20

CREATE OR REPLACE

PACKAGE pac_table3

IS

-- Person Date Comments

-- ITS 08/10/2008

TYPE t_cursor IS REF CURSOR;

PROCEDURE insert_data (

p_name IN VARCHAR2,

p_address IN VARCHAR2,

p_phone IN VARCHAR2

);

PROCEDURE update_data (

p_id IN NUMBER,

p_name IN VARCHAR2,

p_address IN VARCHAR2,

p_phone IN VARCHAR2

);

PROCEDURE delete_data (p_id IN NUMBER);

PROCEDURE select_data (o_cursor OUT t_cursor);

END;

CREATE OR REPLACE

PACKAGE BODY pac_table3

IS

-- Person Date Comments

-- ITS 08/10/2008

PROCEDURE insert_data (

p_name IN VARCHAR2,

p_address IN VARCHAR2,

p_phone IN VARCHAR2

)

IS

BEGIN

INSERT INTO table3

(ID, NAME, address, phone

)

VALUES (table3_seq.NEXTVAL, p_name, p_address, p_phone

);

commit;

END;

PROCEDURE update_data (

p_id IN NUMBER,

p_name IN VARCHAR2,

p_address IN VARCHAR2,

p_phone IN VARCHAR2

)

IS

BEGIN

UPDATE table3

SET NAME = p_name,

address = p_address,

phone = p_phone

WHERE ID = p_id;

END;

PROCEDURE delete_data (p_id IN NUMBER)

IS

BEGIN

DELETE table3

WHERE ID = p_id;

END;

PROCEDURE select_data (o_cursor OUT t_cursor)

IS

BEGIN

OPEN o_cursor FOR

SELECT ID, NAME, address, phone

FROM table3;

END;

END;

Bước 4: Tạo table4, table4_seq, pac_table4 (bao gồm body)

CREATE TABLE table4

(ID NUMBER(12,0),

NAME VARCHAR2(100),

address VARCHAR2(200),

phone VARCHAR2(25))

PCTFREE 10

INITRANS 1

MAXTRANS 255

TABLESPACE users

STORAGE (

INITIAL 65536

MINEXTENTS 1

MAXEXTENTS 2147483645

)

NOCACHE

NOMONITORING

CREATE SEQUENCE table4_seq

INCREMENT BY 1

START WITH 1

MINVALUE 1

MAXVALUE 999999999999999999999999999

NOCYCLE

NOORDER

CACHE 20

CREATE OR REPLACE

PACKAGE pac_table4

IS

-- Person Date Comments

-- ITS 08/10/2008

TYPE t_cursor IS REF CURSOR;

TYPE array_id IS TABLE OF NUMBER

INDEX BY PLS_INTEGER;

TYPE array_name IS TABLE OF VARCHAR (100)

INDEX BY PLS_INTEGER;

TYPE array_address IS TABLE OF VARCHAR (200)

INDEX BY PLS_INTEGER;

TYPE array_phone IS TABLE OF VARCHAR (25)

INDEX BY PLS_INTEGER;

PROCEDURE insert_data_asso (

p_name IN array_name,

p_address IN array_address,

p_phone IN array_phone

);

PROCEDURE update_data_asso (

p_id IN array_id,

p_name IN array_name,

p_address IN array_address,

p_phone IN array_phone

);

PROCEDURE delete_data_asso (p_id IN array_id);

PROCEDURE select_data (o_cursor OUT t_cursor);

END;

CREATE OR REPLACE

PACKAGE BODY pac_table4

IS

-- Person Date Comments

-- ITS 08/10/2008

PROCEDURE insert_data_asso (

p_name IN array_name,

p_address IN array_address,

p_phone IN array_phone

)

IS

BEGIN

FORALL i IN p_name.FIRST .. p_name.LAST

INSERT INTO table4

(ID, NAME, address,

phone

)

VALUES (table4_seq.NEXTVAL, p_name (i), p_address (i),

p_phone (i)

);

END;

PROCEDURE update_data_asso (

p_id IN array_id,

p_name IN array_name,

p_address IN array_address,

p_phone IN array_phone

)

IS

BEGIN

FORALL i IN p_id.FIRST .. p_id.LAST

UPDATE table4

SET NAME = p_name (i),

address = p_address (i),

phone = p_phone (i)

WHERE ID = p_id (i);

END;

PROCEDURE delete_data_asso (p_id IN array_id)

IS

BEGIN

FORALL i IN p_id.FIRST .. p_id.LAST

DELETE table4

WHERE ID = p_id (i);

END;

PROCEDURE select_data (o_cursor OUT t_cursor)

IS

BEGIN

OPEN o_cursor FOR

SELECT ID, NAME, address, phone

FROM table4;

END;

END;

CHẠY CHƯƠNG TRÌNH

Bước 1:

Kiểm tra kết nối database.

Lớp thực thi việc kết nối và đóng kết nối, xem file ODPConnection.cs

using System;

using Oracle.DataAccess.Client;

namespace ODP_Demo

{

///

/// ODPConnection

///

/// ITS

/// 11/10/2008

public class ODPConnection : IDisposable

{

#region contruction

bool isDisposed = false;

private string connString = "";

private OracleConnection connection;

public ODPConnection(string pConnString)

{

this.connString = pConnString;

}

#endregion

#region Open and Close

///

/// Open Connection

///

/// OracleConnection

public OracleConnection Open()

{

try

{

connection = new OracleConnection(connString);

connection.Open();

}

catch

{

connection = null;

}

return connection;

}

///

/// Close Connection

///

public void Close()

{

try

{

if (this.connection != null && this.connection.State != System.Data.ConnectionState.Closed)

{

this.connection.Close();

connection.Dispose();

}

}

catch { }

}

#endregion

#region IDisposable

// Other managed resource this class uses.

private System.ComponentModel.Component component = new System.ComponentModel.Component();

~ODPConnection()

{

Dispose(false);

}

public void Dispose()

{

Dispose(true);

GC.SuppressFinalize(this);

}

protected virtual void Dispose(bool disposing)

{

if (!isDisposed)

{

if (disposing)

component.Dispose();

this.Close();

isDisposed = true;

}

}

#endregion

}

}

Bước 2: Tạo file dữ liệu để Insert vào database.

Xem chi tiết tại file iFunctions.cs

Phương thức tạo ngẫu nhiên một thông tin liên hệ, gồm tên, địa chỉ và số điện thoại.

private static string[] CreateContact(int i)

{

string[] item = new string[3];

Random random = new Random(i + new Random().Next(9999));

//Create Name

string[] firstName = new string[] { "Lê ", "Phạm ", "Nguyễn ", "Trần ", "Phan ", "Huỳnh ", "Hoàng ", "Võ ", "Đoàn " };

string[] middleName = new string[] { "Đức ", "Thúy ", "Minh ", "Phương ", "Quốc ", "Vĩnh ", "Ngọc ", "Quang ", "Hồng " };

string[] lastName = new string[] { "Tâm", "An", "Sơn", "Tuấn", "Trí", "Dũng", "Hương", "Trang", "Hằng" };

item[0] = firstName[random.Next(firstName.Length)] + middleName[random.Next(middleName.Length)] + lastName[random.Next(lastName.Length)];

//Create Address

string[] streets = new string[] { " Nguyễn Huệ, P.", " Lê Lợi, P.", " Hàm Nghi, P.", " Nam Kỳ Khởi Nghĩa, P.", " Võ Thị Sáu, P.", " Điện Biên Phủ, P.", " Trương Quyền, P.", " Phạm Ngọc Thạch, P." };

item[1] = random.Next(200).ToString() + streets[random.Next(streets.Length)] + random.Next(20).ToString() + ", Q." + random.Next(12).ToString() + ", TP.Hồ Chí Minh";

//Create Phone

string[] prefixNumber = new string[] { "090", "093", "0122", "091", "098", "095" };

item[2] = prefixNumber[random.Next(prefixNumber.Length)] + random.Next(9999999).ToString().PadRight(7,'0');

return item;

}

Phương thức lưu tập tin C:\\data_content.xm , chứa count số tài khoản cần tạo ngẫu nhiên.

public static bool WriteContacts(int count)

{

XmlTextWriter writer = null;

try

{

writer = new XmlTextWriter("C:\\data_content.xml", Encoding.UTF8);

writer.WriteStartDocument();

writer.WriteStartElement("contacts");

for (int i = 0; i <>

{

string[] item = CreateContact(i);

writer.WriteStartElement("name");

writer.WriteString(item[0]);

writer.WriteEndElement();

writer.WriteStartElement("address");

writer.WriteString(item[1]);

writer.WriteEndElement();

writer.WriteStartElement("phone");

writer.WriteString(item[2]);

writer.WriteEndElement();

}

writer.WriteEndDocument();

return true;

}

catch

{

return false;

}

finally

{

if(writer != null)

writer.Close();

}

}

Trong file FromMain.cs line 30, số tài khoản cần tạo đang mặc định là 10000. Lưu ý là bạn không nên tạo nhiều số tài khoản, vì khi bạn tiến hành bind dữ liệu lớn thì có thể gặp lỗi ví dụ như sau: ORA-01044: size 5700000 of buffer bound to variable exceeds maximum 4194304.

Việc kiểm tra buffer size, để tiến hành bind từng phần dữ liệu sẽ thảo luận sau.

Bước 3: Tiến hành Insert dữ liệu vào database. Xem chi tiết tại file ODPController.cs.

Trong chương trình này chúng ta sẽ kiểm tra thời gian insert dữ liệu vào database bằng 4 cách.

Cách 1 là dùng theo command text bình thường. Trong trường hợp này chúng ta gửi 10000 command đi đi về về yêu cầu insert về cho database server, và câu lệnh sẽ được biên dịch trước khi thực thi.

public static bool CTInsertData(OracleConnection pConnection, string[] pName, string[] pAddress, string[] pPhone)

{

OracleCommand command = new OracleCommand("INSERT INTO table1(ID, NAME, address, phone) VALUES(table1_seq.NEXTVAL, :p_name, :p_address, :p_phone)", pConnection);

command.CommandType = CommandType.Text;

try

{

for (int i = 0; i <>

{

//Bind Parameter

OracleParameter p_name = new OracleParameter("p_name", OracleDbType.Varchar2);

p_name.Direction = ParameterDirection.Input;

p_name.Value = pName[i];

command.Parameters.Add(p_name);

OracleParameter p_address = new OracleParameter("p_address", OracleDbType.Varchar2);

p_address.Direction = ParameterDirection.Input;

p_address.Value = pAddress[i];

command.Parameters.Add(p_address);

OracleParameter p_phone = new OracleParameter("p_phone", OracleDbType.Varchar2);

p_phone.Direction = ParameterDirection.Input;

p_phone.Value = pPhone[i];

command.Parameters.Add(p_phone);

command.ExecuteNonQuery();

command.Parameters.Clear();

}

return true;

}

catch

{

return false;

}

finally

{

command.Dispose();

}

}

Mất tổng thời gian để insert 10000 record là 10.406 giây

Cách 2 dùng store procedure. Trong trường hợp này chúng ta gửi 10000 command đi đi về về yêu cầu insert về cho database server, và câu lệnh đã được biên dịch sẳn.

public static bool SPInsertData(OracleConnection pConnection, string[] pName, string[] pAddress, string[] pPhone)

{

OracleCommand command = new OracleCommand("pac_table2.insert_data", pConnection);

command.CommandType = CommandType.StoredProcedure;

try

{

for (int i = 0; i <>

{

//Bind Parameter

OracleParameter p_name = new OracleParameter("p_name", OracleDbType.Varchar2);

p_name.Direction = ParameterDirection.Input;

p_name.Value = pName[i];

command.Parameters.Add(p_name);

OracleParameter p_address = new OracleParameter("p_address", OracleDbType.Varchar2);

p_address.Direction = ParameterDirection.Input;

p_address.Value = pAddress[i];

command.Parameters.Add(p_address);

OracleParameter p_phone = new OracleParameter("p_phone", OracleDbType.Varchar2);

p_phone.Direction = ParameterDirection.Input;

p_phone.Value = pPhone[i];

command.Parameters.Add(p_phone);

command.ExecuteNonQuery();

command.Parameters.Clear();

}

return true;

}

catch

{

return false;

}

finally

{

command.Dispose();

}

}

Mất tổng thời gian để insert 10000 record là 9.719 giây

Cách 3 dùng Array Binding, ưu điểm của cách này là chúng ta sẽ add parameters cho command, và chỉ một lần gửi yêu cầu tới database server, như vậy chúng ta sẽ đỡ tốn thời gian đi đi về về mỗi lần Execute command. Điểm cần để ý ở đây là command.ArrayBindCount = pName.Length; báo cho database server tiến hành Execute theo số tham số, ví dụ chúng ta cần insert vào 10000 record thông tin liên lạc, thì sẽ add vào 10000 các parameter tương ứng và sẽ gửi 1 lần yêu cầu cho database server. Database server sẽ tiến hành execute 10000 lần store procedure mà chỉ tốn một lần gửi yêu cầu tới.

public static bool ABInsertData(OracleConnection pConnection, string[] pName, string[] pAddress, string[] pPhone)

{

OracleCommand command = new OracleCommand("pac_table3.insert_data", pConnection);

command.CommandType = CommandType.StoredProcedure;

command.ArrayBindCount = pName.Length;

//Bind Parameter

OracleParameter p_name = new OracleParameter("p_name", OracleDbType.Varchar2);

p_name.Direction = ParameterDirection.Input;

p_name.Value = pName;

command.Parameters.Add(p_name);

OracleParameter p_address = new OracleParameter("p_address", OracleDbType.Varchar2);

p_address.Direction = ParameterDirection.Input;

p_address.Value = pAddress;

command.Parameters.Add(p_address);

OracleParameter p_phone = new OracleParameter("p_phone", OracleDbType.Varchar2);

p_phone.Direction = ParameterDirection.Input;

p_phone.Value = pPhone;

command.Parameters.Add(p_phone);

try

{

command.ExecuteNonQuery();

return true;

}

catch

{

return false;

}

finally

{

p_name.Dispose();

p_address.Dispose();

p_phone.Dispose();

command.Dispose();

}

}

Mất tổng thời gian để insert 10000 record là 3 giây

Cách 4 Dùng PL/SQL Associative Arrays. Ưu điểm của cách này hơn Array Binding ở chỗ là đối với Array Binding thì database server sẽ tiến hành execute 10000 lần SP, thì dùng cách này database server sẽ chỉ tiến hành 1 lần execute SP và cũng chỉ mất một lần đi đi về về triệu gọi thực thi command. Điểm cần lưu ý ở đây là sử dụng OracleCollectionType.PLSQLAssociativeArray;

public static bool AAInsertData(OracleConnection pConnection, string[] pName, string[] pAddress, string[] pPhone)

{

OracleCommand command = new OracleCommand("pac_table4.insert_data_asso", pConnection);

command.CommandType = CommandType.StoredProcedure;

//Bind Parameter

OracleParameter p_name = new OracleParameter("p_name", OracleDbType.Varchar2);

p_name.CollectionType = OracleCollectionType.PLSQLAssociativeArray;

p_name.Direction = ParameterDirection.Input;

p_name.Value = pName;

p_name.Size = pName.Length;

command.Parameters.Add(p_name);

OracleParameter p_address = new OracleParameter("p_address", OracleDbType.Varchar2);

p_address.CollectionType = OracleCollectionType.PLSQLAssociativeArray;

p_address.Direction = ParameterDirection.Input;

p_address.Value = pAddress;

p_address.Size = pAddress.Length;

command.Parameters.Add(p_address);

OracleParameter p_phone = new OracleParameter("p_phone", OracleDbType.Varchar2);

p_phone.CollectionType = OracleCollectionType.PLSQLAssociativeArray;

p_phone.Direction = ParameterDirection.Input;

p_phone.Value = pPhone;

p_phone.Size = pPhone.Length;

command.Parameters.Add(p_phone);

try

{

command.ExecuteNonQuery();

return true;

}

catch

{

return false;

}

finally

{

p_name.Dispose();

p_address.Dispose();

p_phone.Dispose();

command.Dispose();

}

}

Mất tổng thời gian để insert 10000 record là 0.578 giây

Bước 4: Select dữ liệu, kiểm tra sự thay đổi thời gian khi thay đổi FetchSize. Như chúng ta đã biết khi select dữ liệu thì databae server sẽ trả về từng gói dữ liệu nhỏ hơn hoặc bằng FetchSize, như vậy việc linh động sử dụng FetchSize thì sẽ cho chúng ta được thời gian select nhu mong muốn. Ví dụ nếu cần càng nhiều dữ liệu sớm thì chúng ta cần FetchSize lớn, hoặc nếu chúng ta chỉ cần show một phần đầu của dữ liệu thì có thể sử dụng FetchSize nhỏ, phần còn lại sẽ được tiếp tục duyệt.

public static ArrayList SPSelectData(OracleConnection pConnection, uint pCountRecords)

{

OracleCommand command = new OracleCommand("pac_table2.select_data", pConnection);

command.CommandType = CommandType.StoredProcedure;

OracleParameter o_cursor = new OracleParameter("o_cursor", OracleDbType.RefCursor);

o_cursor.Direction = ParameterDirection.Output;

command.Parameters.Add(o_cursor);

OracleDataReader reader = null;

try

{

reader = command.ExecuteReader();

ArrayList list = new ArrayList(1000);

//long temSize = command.RowSize * pCountRecords;

long tempSize = 337 * pCountRecords;

//if(tempSize <>

// tempSize = 65536

reader.FetchSize = tempSize;

while (reader.Read())

{

TableInfo info = new TableInfo();

info.ID = reader.GetDecimal(0);

info.NAME = reader.GetString(1);

info.ADDRESS = reader.GetString(2);

info.PHONE = reader.GetString(3);

list.Add(info);

}

if (list.Count > 0)

return list;

else

return null;

}

catch

{

return null;

}

finally

{

if (reader != null)

{

if (!reader.IsClosed)

reader.Close();

reader.Dispose();

}

command.Dispose();

}

}

Lần 1: select 10000 records một lần mất 1.609 giây

Lần 2: select 1000 records một lần mất 1.906 giây

Lần 3: select 1 records một lần mất 6.172 giây

Bài viết về cơ bản ODP.NET tạm dừng tại đây, rất mong nhận được sự đóng góp ý kiến của các bạn để có thể hoàn thiện hơn.




Các bạn tải chi tiết bài viết và mã nguồn chương trình theo link dưới đây.
http://cid-60a6680ce5dc0825.office.live.com/self.aspx/Programing/ODP%5E_NET.rar

Lê Đức Tâm

5 comments:

Unknown said...

Dài quá, đọc không nổi

http://www.oracle.com/technetwork/topics/dotnet/whatsnew/oracle-entity-framework-sod-130214.pdf

Lê Đức Tâm said...

Viết step by step cho những người begin mà. ^^

[VN]hanh090 said...

Thank lớn!

Nguyễn Bá Nam said...
This comment has been removed by the author.
Nguyễn Bá Nam said...

Có phải xml làm nhiệm vụ tạo dữ liệu, rồi sử dụng dữ liệu ấy để chèn vào database và sau đó từ database đưa lên form không? Mình đã tạo được dblink và muốn select để tìm kiếm ở local db và remote db, tức là nếu không tìm thấy ở db này thì tìm ở db kia. Mình có thể sử dụng cursor trong procedure được không và mình phải viết nó thế nào? À, mà khi thực thi 1 khối câu lệnh nào đó trong sql developer có nhất thiết phải bôi đen toàn bộ câu lệnh đó hay không? Cảm ơn bạn đã quan tâm.