블로그 이미지
Sunny's

calendar

1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

Notice

2009. 11. 4. 10:46 .NET Framework

Data Access Application Block(DAAB)는 데이터베이스 관련작업을 단순화 하기 위한 어플리케이션 블록입니다.
DAAB는 SQL Server와 Oracle에 대해 작업할 수 있는 여러 클래스들을 포함하고 있습니다. 그리고 어플리케이션코드가 특정 데이터베이스를 "Cusomter" 또는 "Inventory"과 같이 ADO.NET 연결 문자열명을 통해서 참조할 수있게 해줍니다.
이와 같이 어플리케이션 코드는 데이터베이스의 named instance를 명시할 수 있게 되며 이 named instance를DatabaseFactory.CreateDatabase 메서드의 파라미터로 넘겨줌으로써 해당 데이터베이스로의 연결을 가지게됩니다.
각각의 named 데이터베이스는 구성파일에 저장된 연결 정보을 가지고 있으며, 구성 파일에서 이 설정을 변경함으로써, 개발자들은 어플리케이션이 코드의 재컴파일 없이도 다른 데이터베이스 구성을 사용할 수 있도록 할 수 있습니다.

개발자들은 데이터베이스 작업을 하기위해 반복적인 코딩을 수행해야 하고, 데이터베이스 타입을 변경하려면 적지않은 노력을 들여야 했습니다.

DAAB 사용을 하게 되면,
- ADO.NET 2.0이 제공하는 기능을 사용할 수 있습니다.
- 데이터베이스 관련 표준적인 작업을 위한 코드를 감소할 수 있습니다.
- 어플리케이션 내에서 일관된 데이터 접근 수행을 유지할 수 있습니다.
- 손쉽게 데이터베이스 타입을 변경할 수 있습니다.

아래는 "도움말"이 보여주는 EAAB 의 클래스 구성입니다. 참고합시다.


EAAB를 사용하는 일반적인 샘플을 봅니다.




//구성파일에 명시된 DEFAULT NAMED INSTANCE를 가져옵니다.

Database db = DatabaseFactory.CreateDatabase();

// SP 명령객체를 생성합니다.

DbCommand dbCommand = db.GetStoredProcCommand("GetProductsByCategory");



// 파라미터를 전달합니다.

// Retrieve products from category 7.

db.AddInParameter(dbCommand, "CategoryID", DbType.Int32, 7);



//명령을 수행하여 데이터셋을 가져옵니다.

DataSet productDataSet = db.ExecuteDataSet(dbCommand);


코드 상에서 굳이 연결 객체를 생성하고 연결문자열 전달하고, 연결 오픈해서, 명령객체 생성 후 파라미터 객체 생성후 명령객체에전달한 후, 명령객체의 연결객체를 지정한 후, 명령객체 실행하여, 데이터셋 객체를 가져오는 식의 반복적인 데이터베이스 관련작업을
위 처럼 간소화 할 수 있다는 점이 이점
또한 손쉽게 연결문자열을 구성파일에서 변경하여 재컴파일없이 다른 데이터베이스로 작업을 손쉽게 변경할 수 있다는 이점,
연결객체에 대한 OPEN/CLOSE 및 객체의 Disposing은 EAAB 내부적으로 처리해 주므로 이에 대해 신경쓸 필요없다는 이점,
그리고 이것이 Best Practice라는 이점.

그야말로 개발자들에게 하부의 데이터베이스 작업(코드)를 Transparent 하게 해주는 고마운 EAAB 입니다.

구성 생성하기
Enterprise Library Configuration을 실행합니다.
새로운 어플리케이션을 추가합니다.
Data Access Application Block을 추가합니다.



Connection Strings 하위에 named instance를 선택하고 그 이름을 의미있는 이름으로 변경합니다.
ProviderName으로 지정할 수 있는 옵션 중에서 SQL Server를 사용할 것이므로 System.Data.SqlClient로 선택합니다.



"Sales" Named instance 하위에 여러 파라미터들을 지정할 수 있습니다.
기본으로 생성된 파라미터 중에서 Database 는 사용할 데이터베이스명,
Server 는 사용할 데이터베이스 서버명으로 그 값을 지정해 둡니다.
SQL Server Login으로 접근토록 할 것이므로, Integrated Security는 삭제하고,
파라미터 User Id, Password 두개를 추가합니다.
그리고 그 값을 각각 사용할 데이터베이스 로그인과 암호로서 설정합니다.


Data Access Application Block 노드를 선택하고 DefaultDatabase 속성 값이 Sales로 선택된것을 확인한다. 이 속성값이 어플리케이션 코드에서 default named instance로 사용될 named instance입니다.

위와 같은 과정을 반복해서 여러 개의 named instance를 생성해 둘 수 있으며, 이 구성파일을 가지는 어플리케이션에서 사용할 수 있습니다.

어플리케이션 구성파일로 저장합니다.(app.config 또는 web.config) :

EAAB를 어플리케이션에서 사용

1. 어셈블리 참조 추가
Microsoft.Practices.EnterpriseLibrary.Data.dll
Microsoft.Practices.EnterpriseLibrary.Common.dll

2. Using 문 추가(optional)


using Microsoft.Practices.EnterpriseLibrary.Data;
using System.Data;

3. Database 객체 생성


//default named instance를 가져옴 ' Sales

Database db = DatabaseFactory.CreateDatabase();

또는

// 특정 named instance를 가져옴

Database db = DatabaseFactory.CreateDatabase("Sales");




만일 생성하고자하는 데이터베이스의 연결문자열을 알고 있다면, 어플리케이션 구성정보를 무시하고, 생성자를 통해 Database객체를 생성할 수 있습니다. Database 클래스는 추상 기본 클래스(abstract base class) 이므로, 이를상속한 클래스의 객체를 생성해야 합니다.
상속된 클래스로는 SqlDatabase, OracleDatabase가 있는데, SqlDatabase는SqlClientFactory 프로바이더, OracleDatabase는 OracleClientFactory 프로바이더를 사용하여SQL Server, Oracle 용으로 사용합니다.



// Assume the method GetConnectionString exists in your application and

// returns a valid connection string.

string myConnectionString = GetConnectionString();

SqlDatabase sqlDatabase = new SqlDatabase(myConnectionString);


SQL Server난 Oracle이 아닌 서버에 작업을 해야 하는 경우에는 GeneriicDatabase 객체를 생성할 수 있으며, 이를 사용할 때 반드시 DbProviderFactory 객체를 제공해야 합니다.


GenericDatabase db = new GenericDatabase(connectionString, OdbcFactory.Instance);



4. DbCommand 객체 생성
EAAB는 ADO.NET DbCommand 객체를 가져오기 위한 일관된 방법을 제공합니다.
이 객체를 이용해서 여러 output 파라미터를 결과로서 리턴하는 SP를 호출할 수 있으며, SP의 타임아웃 값을 명시할 수도 있습니다.

- SQL 구문을 위한 DbCommand 객체


Database db = DatabaseFactory.CreateDatabase();

string sqlCommand = "Select CustomerID, LastName, FirstName From Customers";

DbCommand dbCommand = db.GetSqlStringCommand(sqlCommand);


- SP를 위한 DbCommand 객체


Database db = DatabaseFactory.CreateDatabase();

DbCommand dbCommand = db.GetStoredProcCommand("GetProductsByCategory");



5. 연결관리

데이터베이스 연결을 매우 비싼 자원입니다. 즉 메모리나 cpu 등 컴퓨터의 자원을 많이 잡아먹는 종류의 자원입니다. 따라서 이를 사용하는 어플리케이션은 주의를 기울여서 사용하도록 해서, 시스템 성능을 보호할 의무가 있습니다.
데이터베이스 연결은 필요한 동안에만 open하여 사용하고, 가능한 한 빨리 close 하는 것이 가장 바람직합니다.
Database 객체의 메서드들은 각 호출 시 마다 데이터베이스 연결의 open/close를 처리합니다. 그러므로, 어플리케이션 코드는 연결을 관리하기 위한(open/close) 코드를 포함 할 필요가 없습니다.
(성능상의 이유로, ADO.NET은 연결을 CLOSE 하지 않고 연결 풀로 반환하므로, 우리는 Database 객체를 캐시할 필요가 없습니다.)


Database db = DatabaseFactory.CreateDatabase();



string sqlCommand = "Select ProductID, ProductName From Products";

DbCommand dbCommand = db.GetSqlStringCommand(sqlCommand);



// No need to open the connection; just make the call.

DataSet customerDataSet = db.ExecuteDataSet(dbCommand);



그러나 언제 연결을 close해야 할지 명확하지 않은 예외 케이스가 존재하는데 그 예가 ExcuteReader 메서드 입니다.이 메서드는 DbDataReader 객체를 리턴하게 되는데, 이는 필요시에 데이터의 특정 영역을 읽도록, 즉 데이터베이스 연결이필요하도록 디자인되었습니다. 다른 말로, 어플리케이션이 언제 이 객체가 더 이상 필요치 않게 될지 알 수 없다는 것입니다.
필요한 작업을 다 수행한 뒤, DbDataReader.close를 호출하여 연결을 Close해야 합니다.
그래서 이 메서드를 사용해야 하는 경우에는 아래 처럼 using() 구문을 사용해서 DbDataReader 객체가 Close 되도록 강제하여 dispose 되도록 해 주어야 합니다.


Database db = DatabaseFactory.CreateDatabase();



DbCommand dbCommand = db.GetSqlStringCommand("Select Name, Address From Customers");

using (IDataReader dataReader = db.ExecuteReader(dbCommand))

{

// Process results

}



또는



Database db = DatabaseFactory.CreateDatabase();

DbCommand dbCommand = db.GetStoredProcCommand("GetProductsByCategory");



IDataReader dataReader = null;



try

{

//...

dataReader = db.ExecuteReader(dbCommand);

}

catch(Exception ex)

{

// Process exception

}

finally

{

if (dataReader != null)

dataReader.Close();

}




5. Parameter Handling

- AddParameter : This method passes a parameter (input or output) to a stored procedure.
- AddInParameter : This method passes an input parameter to a stored procedure.
- AddOutParameter :. This method adds an output parameter to a stored procedure.
- GetParameterValue : This method finds the value of the specified parameter.
- SetParameterValue : This method sets the value of the specifiedparameter when you want to do multiple inserts using the sameconnection and command but with different parameter values.


주요 시나리오별 샘플 코드

여러 레코드를 조회하기 위해 DbDataReader 사용하기



Database db = DatabaseFactory.CreateDatabase();



using (IDataReader dataReader = db.ExecuteReader(CommandType.Text, "Select Name, Address, City From Customers" ))

{

customerGrid.DataSource = dataReader;

customerGrid.DataBind();

}



여러 레코드를 조회하기 위해 DataSet 사용하기


Database db = DatabaseFactory.CreateDatabase();



string sqlCommand = "GetProductsByCategory";

DbCommand dbCommand = db.GetStoredProcCommand(sqlCommand);



// Retrieve products from category 7.

int category = 7;

db.AddInParameter(dbCommand, "CategoryID", DbType.Int32, category);



DataSet productDataSet = db.ExecuteDataSet(dbCommand);




명령 수행과 Output 파라미터에 접근하기


Database db = DatabaseFactory.CreateDatabase();



string sqlCommand = "GetProductDetails";

DbCommand dbCommand = db.GetStoredProcCommand(sqlCommand);



db.AddInParameter(dbCommand, "ProductID", DbType.Int32, 3);

db.AddOutParameter(dbCommand, "ProductName", DbType.String, 50);

db.AddOutParameter(dbCommand, "UnitPrice", DbType.Currency, 8);



db.ExecuteNonQuery(dbCommand);



string results = string.Format(CultureInfo.CurrentCulture, "{0}, {1}, {2:C} ",

db.GetParameterValue(dbCommand, "ProductID"),

db.GetParameterValue(dbCommand, "ProductName"),

db.GetParameterValue(dbCommand, "UnitPrice"));




명령 수행과 Single-Item 결과 접근하기


Database db = DatabaseFactory.CreateDatabase();



string sqlCommand = "GetProductName";

int productId = 7;

DbCommand dbCommand = db.GetStoredProcCommand(sqlCommand, productId);



string productName = (string)db.ExecuteScalar(dbCommand);




Transaction 내에서 여러 건의 갱신 처리하기

ADO.NET 2.0에서는 TransactionScope 객체를 사용해서 트랜잭션 처리를 수행합니다. 아래의 코드는 사용하지 않았습니다. ' 추후 TransactionScope 객체에 대해 언급하겠습니다.


public bool Transfer(int transactionAmount, int sourceAccount, int destinationAccount)

{

bool result = false;



// Create the database object, using the default database service. The

// default database service is determined through configuration.

Database db = DatabaseFactory.CreateDatabase();



// Two operations, one to credit an account, and one to debit another

// account.

string sqlCommand = "CreditAccount";

DbCommand creditCommand = db.GetStoredProcCommand(sqlCommand);



db.AddInParameter(creditCommand, "AccountID", DbType.Int32, sourceAccount);

db.AddInParameter(creditCommand, "Amount", DbType.Int32, transactionAmount);



sqlCommand = "DebitAccount";

DbCommand debitCommand = db.GetStoredProcCommand(sqlCommand);



db.AddInParameter(debitCommand, "AccountID", DbType.Int32, destinationAccount);

db.AddInParameter(debitCommand, "Amount", DbType.Int32, transactionAmount);



using (DbConnection connection = db.CreateConnection())

{

connection.Open();

DbTransaction transaction = connection.BeginTransaction();



try

{

// Credit the first account.

db.ExecuteNonQuery(creditCommand, transaction);

// Debit the second account.

db.ExecuteNonQuery(debitCommand, transaction);



// Commit the transaction.

transaction.Commit();



result = true;

}

catch

{

// Roll back the transaction.

transaction.Rollback();

}

connection.Close();



return result;

}

}





데이터베이스 갱신을 위해 DataSet 사용하기
Database db = DatabaseFactory.CreateDatabase();



DataSet productsDataSet = new DataSet();



string sqlCommand = "Select Select ProductID, ProductName, CategoryID, UnitPrice, LastUpdate From Products";

DbCommand dbCommand = db.GetSqlStringCommand(sqlCommand);



string productsTable = "Products";



// Retrieve the initial data.

db.LoadDataSet(dbCommand, productsDataSet, productsTable);



// Get the table that will be modified.

DataTable table = productsDataSet.Tables[productsTable];



// Add a new product to existing DataSet.

DataRow addedRow = table.Rows.Add(new object[] {DBNull.Value, "New product", 11, 25});



// Modify an existing product.

table.Rows[0]["ProductName"] = "Modified product";



// Establish the Insert, Delete, and Update commands.

DbCommand insertCommand = db.GetStoredProcCommand("AddProduct");

db.AddInParameter(insertCommand, "ProductName", DbType.String, "ProductName", DataRowVersion.Current);

db.AddInParameter(insertCommand, "CategoryID", DbType.Int32, "CategoryID", DataRowVersion.Current);

db.AddInParameter(insertCommand, "UnitPrice", DbType.Currency, "UnitPrice", DataRowVersion.Current);



DbCommand deleteCommand = db.GetStoredProcCommand("DeleteProduct");

db.AddInParameter(deleteCommand , "ProductID", DbType.Int32, "ProductID", DataRowVersion.Current);



DbCommand updateCommand = db.GetStoredProcCommand("UpdateProduct");

db.AddInParameter(updateCommand, "ProductID", DbType.Int32, "ProductID", DataRowVersion.Current);

db.AddInParameter(updateCommand, "ProductName", DbType.String, "ProductName", DataRowVersion.Current);

db.AddInParameter(updateCommand, "LastUpdate", DbType.DateTime, "LastUpdate", DataRowVersion.Current);



// Submit the DataSet, capturing the number of rows that were affected.

int rowsAffected = db.UpdateDataSet(productsDataSet, "Products", insertCommand, updateCommand, deleteCommand,

Microsoft.Practices.EnterpriseLibrary.Data.UpdateBehavior.Standard);




여러 레코드를 XML (결과)로 가져오기


SqlDatabase dbSQL = DatabaseFactory.CreateDatabase("EntLibQuickStartsSql") as SqlDatabase;



// Use "FOR XML AUTO" to have SQL return XML data.

string sqlCommand = "SELECT ProductID, ProductName FROM Products FOR XML AUTO";

DbCommand dbCommand = dbSQL.GetSqlStringCommand(sqlCommand);



XmlReader productsReader = null;

StringBuilder productList = new StringBuilder();



try

{

productsReader = dbSQL.ExecuteXmlReader(dbCommand);



// Iterate through the XmlReader and put the data into our results.

while (!productsReader.EOF)

{

if (productsReader.IsStartElement())

{

productList.Append(productsReader.ReadOuterXml());

productList.Append(Environment.NewLine);

}

}

}

finally

{

// Close the Reader.

if (productsReader != null)

{

productsReader.Close();

}



// Explicitly close the connection. The connection is not closed

// when the XmlReader is closed.

if (dbCommand.Connection != null)

{

dbCommand.Connection.Close();

}

}



Enterprise Library Application Block은 이정도로 하고 마감합니다.
사실 Security, Offline, Smart Client Composite UI 등 다른 어플리케이션 블록이 존재합니다. Offline 블록은 enSimple 의 다른 글로서 소개 했고,
Security는 실효성이 조금 떨어지는 듯 하여, 배제했으며, Composite UI는 너무 방대하고, 또한 개발자가 이해하고적용해서 쓰기에는 너무 많은 것을 요구하는 듯 하여…(__!) 살짝 제껴두고 갑니다. 후에 필요성이 충분히 확인된다면… 그때가서 다시 ….
끝.

출 처 : http://ultteky.egloos.com/10024784
posted by Sunny's