微软企业库5.0学习笔记(三)

以对象形式从数据库获取数据

  现代的很多编程技术都集中在“数据就是对象”这个概念。如果你在应用层之间使用Data Transfer Objects (DTOs)传输数据的话,这个方法就很有用,使用ORM实现一个数据访问层,或者是客户端查询技术,例如LINQ。

  数据库访问模块实现了这个功能,允许你执行SQL或者是存储过程,可以返回一个对象序列,但是要求序列实现IEnumerable接口。

  关于Accessors

  模块提供了两个方法来实现这种查询要求,SprocAccessor和SqlStringAccessor。你可以使用Database类的ExecuteSprocAccessor和ExecuteSqlStringAccessor,或者是创建一个Accessor,然后调用它的Execute方法。

  下面是一张查询示意图

  微软企业库5.0学习笔记(三)

  Accessor使用另外两个对象,一个用来管理传入accessor的参数,一个用来将数据库返回的数据行映射成客户端需要的对象。

  如果你没有指定一个参数映射,accessor会使用默认的参数映射。默认情况下这个功能只能用于执行SQL Server和Oracle的存储过程。不能执行SQL 语句,或者是其他的数据库和provider,如果需要的话,可以自定义参数映射器。

  如果你没有指定一个对象映射,模块使用默认的对象映射,根据列的名称映射到对象的属性。你也可以自定义对象映射,将列映射到指定的对象属性上去。

  创建和执行Accessor

  

 

代码
//  Create an object array and populate it with the required parameter values
object []  params   =   new   object [] {  " %bike% "  };
//  Create and execute a sproc accessor that uses the default
//  parameter and output mappings.
var productData  =  defaultDB.ExecuteSprocAccessor < Product > ( " GetProductList " ,
params );
//  Perform a client‐side query on the returned data. Be aware that
//  the orderby and filtering is happening on the client, not in the database.
var results  =  from productItem  in  productData
where  productItem.Description  !=   null
orderby productItem.Name
select 
new  { productItem.Name, productItem.Description };
//  Display the results
foreach  (var item  in  results)
{
A Guide to Developing with Enterprise Library 
5.0   41
Console.WriteLine(
" Product Name: {0} " , item.Name);
Console.WriteLine(
" Description: {0} " , item.Description);
Console.WriteLine();
}

 

 

  上面假设由一个Product类,有ID,Name,Description三个属性。

  创建和使用映射Mappers

  在某些情况下,你需要自定义参数映射,将你的参数传递给要执行查询的accessor。这种典型的情况发生在,你需要执行一个SQL语句,和一个不支持参数的数据库进行交互,或者是默认的参数映射的参数个数或者是类型不匹配。参数映射类需要实现IParameterMapper接口,有一个AssignParameters方法引用了Command对象作为参数,你需要做的就是将需要的参数加入Command对象的Parameters集合。

  在更多的情况你需要一个自定义对象映射。为了帮助你完成这个需求,模块提供了MapBuilder类,用它可以创建列和对象属性的映射关系。

  默认情况,accessor可以返回一个简单的对象序列。但是,有时候需要返回一个复杂的对象序列,例如,返回Orders的同时返回相关的OrderLines。简单的映射不能满足这样的需求,MapBuilder类也不能满足了。你需要实现IResultSetMapper接口,自定义对象映射关系。

  获取XML数据

  企业库提供了ExecuteXmlReader方法返回一个XmlReader对象。目前为止,还只能支持SQL Server数据库,意味着你只能用SqlDatabase类。

  你需要把Database转换成SqlDatabse,或者是用构造函数直接创建一个SqlDatabse。

  

 

代码
static  SqlDatabase sqlServerDB  =   null ;
//  Resolve a SqlDatabase object from the container using the default database.
sqlServerDB
=  EnterpriseLibraryContainer.Current.GetInstance < Database > ()  as  SqlDatabase;
//  Specify a SQL query that returns XML data
string  xmlQuery  =   " SELECT * FROM OrderList WHERE State = @state FOR XML AUTO " ;
//  Create a suitable command type and add the required parameter
//  NB: ExecuteXmlReader is only available for SQL Server databases
using  (DbCommand xmlCmd  =  sqlServerDB.GetSqlStringCommand(xmlQuery))
{
xmlCmd.Parameters.Add(
new  SqlParameter( " state " " Colorado " ));
using  (XmlReader reader  =  sqlServerDB.ExecuteXmlReader(xmlCmd))
{
while  ( ! reader.EOF)  //  Iterate through the elements in the XmlReader
{
if  (reader.IsStartElement())
{
Console.WriteLine(reader.ReadOuterXml());
}
}
}
}

 

 

  获取单个值

  

 

代码
//  Create a suitable command type for a SQL statement
//  NB: For efficiency, aim to return only a single value or a single row.
using  (DbCommand sqlCmd
=  defaultDB.GetSqlStringCommand( " SELECT [Name] FROM States " ))
{
//  Call the ExecuteScalar method of the command
Console.WriteLine( " Result using a SQL statement: {0} " ,
defaultDB.ExecuteScalar(sqlCmd).ToString());
}
//  Create a suitable command type for a stored procedure
//  NB: For efficiency, aim to return only a single value or a single row.
using  (DbCommand sprocCmd  =  defaultDB.GetStoredProcCommand( " GetStatesList " ))
{
//  Call the ExecuteScalar method of the command
Console.WriteLine( " Result using a stored procedure: {0} " ,
defaultDB.ExecuteScalar(sprocCmd).ToString());
}

 

  异步获取数据

  1)准备配置文件

  需要在连接字符串中添加Asynchronous Processing=true或者是async=true。

  

 

代码
< connectionStrings >
< add name = " AsyncExampleDatabase "
connectionString
= " Asynchronous Processing=true; Data Source=.\SQLEXPRESS;
Initial Catalog = " MyDatabase " ; Integrated Security = True; "
providerName = " System.Data.SqlClient "   />
...
</ connectionStrings >

 

  另外,企业库中的异步访问数据库只支持SQL Server。在Database类由一个属性SupportsAsync,可以用来查询当前数据库是否支持异步访问。

  

 

 

 

代码
private   static   bool  SupportsAsync(Database db)
{
if  (db.SupportsAsync)
{
Console.WriteLine(
" Database supports asynchronous operations " );
return   true ;
}
Console.WriteLine(
" Database does not support asynchronous operations " );
return   false ;
}

 

  使用异步访问数据库通常需要一个callback,在调用端会打开另外一个线程。这个callback通常不会直接访问winform和wpf的用户界面。你需要在用户界面添加事件,然后通过委托的方式更新用户界面。

  委托可以使用Lambda表达式实现。

 

代码
DbCommand cmd  =  asyncDB.GetStoredProcCommand( " ListOrdersSlowly " );
asyncDB.AddInParameter(cmd, 
" state " , DbType.String,  " Colorado " );
asyncDB.AddInParameter(cmd, 
" status " , DbType.String,  " DRAFT " );
//  Execute the query asynchronously specifying the command and the
//  expression to execute when the data access process completes.
asyncDB.BeginExecuteReader(cmd,
asyncResult 
=>
{
//  Lambda expression executed when the data access completes.
try
{
using  (IDataReader reader  =  asyncDB.EndExecuteReader(asyncResult))
{
A Guide to Developing with Enterprise Library 
5.0   47
Console.WriteLine();
DisplayRowValues(reader);
}
}
catch  (Exception ex)
{
Console.WriteLine(
" Error after data access completed: {0} " , ex.Message);
}
}, 
null );

  

 

  异步获取对象形式返回的数据

  

 

代码
object [] paramArray  =   new   object [] {  " %bike% " 20  };
//  Create the accessor. This example uses the simplest overload.
var accessor  =  asyncDB.CreateSprocAccessor < Product > ( " GetProductsSlowly " );
//  Execute the accessor asynchronously specifying the callback expression,
//  the existing accessor as the AsyncState, and the parameter values array.
accessor.BeginExecute(
asyncResult 
=>
//  Lambda expression executed when the data access completes.
try
{
//  Accessor is available via the asyncResult parameter
var acc  =  (IDataAccessor < Product > ) asyncResult.AsyncState;
//  Obtain the results from the accessor.
var productData 
=  acc.EndExecute(asyncResult);
//  Perform a client‐side query on the returned data.
//  Be aware that the orderby and filtering is happening
//  on the client, not inside the database.
var results  =  from productItem  in  productData
where  productItem.Description  !=   null
orderby productItem.Name
select 
new  { productItem.Name, productItem.Description };
//  Display the results
Console.WriteLine();
foreach  (var item  in  results)
{
Console.WriteLine(
" Product Name: {0} " , item.Name);
Console.WriteLine(
" Description: {0} " , item.Description);
Console.WriteLine();
}
}
catch  (Exception ex)
{
Console.WriteLine(
" Error after data access completed: {0} " , ex.Message);
}
}, accessor, paramArray);

 

  更新数据库

  

 

代码
string  oldDescription
=   " Carries 4 bikes securely; steel construction, fits 2\ "  receiver hitch. " ;
string  newDescription  =   " Bikes tend to fall off after a few miles. " ;
//  Create command to execute the stored procedure and add the parameters.
DbCommand cmd  =  defaultDB.GetStoredProcCommand( " UpdateProductsTable " );
defaultDB.AddInParameter(cmd, 
" productID " , DbType.Int32,  84 );
defaultDB.AddInParameter(cmd, 
" description " , DbType.String, newDescription);
//  Execute the query and check if one row was updated.
if  (defaultDB.ExecuteNonQuery(cmd)  ==   1 )
{
//  Update succeeded.
}

else
{
Console.WriteLine(
" ERROR: Could not update just one row. " );
}
//  Change the value of the second parameter
defaultDB.SetParameterValue(cmd,  " description " , oldDescription);
//  Execute query and check if one row was updated
if  (defaultDB.ExecuteNonQuery(cmd)  ==   1 )
{
//  Update succeeded.
}
else
{
Console.WriteLine(
" ERROR: Could not update just one row. " );
}

 

你可能感兴趣的:(学习笔记)