以对象形式从数据库获取数据
现代的很多编程技术都集中在“数据就是对象”这个概念。如果你在应用层之间使用Data Transfer Objects (DTOs)传输数据的话,这个方法就很有用,使用ORM实现一个数据访问层,或者是客户端查询技术,例如LINQ。
数据库访问模块实现了这个功能,允许你执行SQL或者是存储过程,可以返回一个对象序列,但是要求序列实现IEnumerable接口。
关于Accessors
模块提供了两个方法来实现这种查询要求,SprocAccessor和SqlStringAccessor。你可以使用Database类的ExecuteSprocAccessor和ExecuteSqlStringAccessor,或者是创建一个Accessor,然后调用它的Execute方法。
下面是一张查询示意图
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.");
}
未完待续。。。。。。。。。。。。。。。。。。。。。