
Data Access Application Block提供了通用的数据访问的功能,随着2.0版本的推出有了很大变化。
一.改进
在DAAB1.1里面我们知道Database方法返回或者创建一个DBCommandWrapper对象,而在DAAB2.0里面移除了DBCommandWrapper类,用ADO.NET2.0里面的DBCommand类代替实现类似的功能,这样使得DAAB跟我们的.NET类库的结合更加紧密,回忆一下我们在1.1里面用DBCommandWrapper来访问数据时的代码:
Database db = DatabaseFactory.CreateDatabase();

DBCommandWrapper dbCommand = db.GetStoredProcCommandWrapper("GetProductsByCategory");

dbCommand.AddInParameter("CategoryID", DbType.Int32, Category);

DataSet productDataSet = db.ExecuteDataSet(dbCommand);
而用了新的DBCommand类之后则变成了:
Database db = DatabaseFactory.CreateDatabase();

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

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

DataSet productDataSet = db.ExecuteDataSet(dbCommand);
数据库连接字符串在我们基于数据库的开发永远是少不了的,但是在DAAB1.1下,它所使用的字符串跟我们在.NET类库中使用的连接字符串却是不能共享的,它们分别保存在不同的位置。而在2.0的Data Access Application Block使用了ADO.NET2.0里面<connectionStrings>配置区,这样带来的一个好处是连接字符串可以在Application Block和自定义的.NET类之间共享使用该配置区,如:
<connectionStrings>
<add
name="DataAccessQuickStart"
providerName="System.Data.SqlClient"
connectionString="server=(local)\SQLEXPRESS;database=EntLibQuickStarts;Integrated Security=true" />
</connectionStrings>
在.NET2.0下,泛型编程已经成为了一个核心,而2.0版的DAAB中也新增了一个GenericDatabase对象。DAAB中虽然已经包含了SqlDatabase和OrcaleDatabase,但是如果我们需要使用其他的像DB2等数据库时,就需要用到GenericDatabase,它可以用于任何.NET类库中的数据提供者,包括OdbcProvider和OleDbProvider。
二.使用示例
DAAB2.0的配置非常简单,主要有以下几方面的配置:
配置连接字符串

配置默认数据库

添加相关的命名空间:
using Microsoft.Practices.EnterpriseLibrary.Data;
using System.Data;
使用Data Access Application Block进行数据的读取和操作,一般分为三步:
1.创建Database对象
2.提供命令参数,如果需要的话
3.执行命令
下面分别看一下DataAccessQuickStart中提供的一些例子:
执行静态的SQL语句
public string GetCustomerList()


{
// 创建Database对象
Database db = DatabaseFactory.CreateDatabase();
// 使用SQL语句创建DbCommand对象
string sqlCommand = "Select CustomerID, Name, Address, City, Country, PostalCode " +
"From Customers";
DbCommand dbCommand = db.GetSqlStringCommand(sqlCommand);

StringBuilder readerData = new StringBuilder();

// 调用ExecuteReader方法
using (IDataReader dataReader = db.ExecuteReader(dbCommand))


{
while (dataReader.Read())

{
// Get the value of the 'Name' column in the DataReader
readerData.Append(dataReader["Name"]);
readerData.Append(Environment.NewLine);
}
}

return readerData.ToString();
}
执行存储过程并传递参数,返回DataSet
public DataSet GetProductsInCategory(int Category)


{
// Create the Database object, using the default database service. The
// default database service is determined through configuration.
Database db = DatabaseFactory.CreateDatabase();

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

// Retrieve products from the specified category.
db.AddInParameter(dbCommand, "CategoryID", DbType.Int32, Category);

// DataSet that will hold the returned results
DataSet productsDataSet = null;

productsDataSet = db.ExecuteDataSet(dbCommand);

// Note: connection was closed by ExecuteDataSet method call

return productsDataSet;
}
利用DataSet更新数据
public int UpdateProducts()


{
// Create the Database object, using the default database service. The
// default database service is determined through configuration.
Database db = DatabaseFactory.CreateDatabase();

DataSet productsDataSet = new DataSet();

string sqlCommand = "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 our 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, UpdateBehavior.Standard);

return rowsAffected;

}
通过ID获取记录详细信息
public string GetProductDetails(int productID)


{
// Create the Database object, using the default database service. The
// default database service is determined through configuration.
Database db = DatabaseFactory.CreateDatabase();

string sqlCommand = "GetProductDetails";
DbCommand dbCommand = db.GetStoredProcCommand(sqlCommand);

// Add paramters
// Input parameters can specify the input value
db.AddInParameter(dbCommand, "ProductID", DbType.Int32, productID);
// Output parameters specify the size of the return data
db.AddOutParameter(dbCommand, "ProductName", DbType.String, 50);
db.AddOutParameter(dbCommand, "UnitPrice", DbType.Currency, 8);

db.ExecuteNonQuery(dbCommand);

// Row of data is captured via output parameters
string results = string.Format(CultureInfo.CurrentCulture, "{0}, {1}, {2:C} ",
db.GetParameterValue(dbCommand, "ProductID"),
db.GetParameterValue(dbCommand, "ProductName"),
db.GetParameterValue(dbCommand, "UnitPrice"));

return results;
}
以XML格式返回数据
public string GetProductList()


{
// Use a named database instance that refers to a SQL Server database.
SqlDatabase dbSQL = DatabaseFactory.CreateDatabase() as SqlDatabase;

// Use "FOR XML AUTO" to have SQL return XML data
string sqlCommand = "Select ProductID, ProductName, CategoryID, UnitPrice, LastUpdate " +
"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();
}
}

return productList.ToString();
}
使用事务
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

{
// Rollback transaction
transaction.Rollback();
}
connection.Close();
return result;
}
}
三.常见功能
1.创建Database对象
创建一个默认的Database对象
Database dbSvc = DatabaseFactory.CreateDatabase();
默认的数据库在配置文件中:
<dataConfiguration defaultDatabase="DataAccessQuickStart" />
创建一个实例Database对象
// Use a named database instance that refers to an arbitrary database type,
// which is determined by configuration information.
Database myDb = DatabaseFactory.CreateDatabase("DataAccessQuickStart");
创建一个具体的类型的数据库对象
// Create a SQL database.
SqlDatabase dbSQL = DatabaseFactory.CreateDatabase("DataAccessQuickStart") as SqlDatabase;
2.创建DbCommand对象
静态的SQL语句创建一个DbCommand
Database db = DatabaseFactory.CreateDatabase();
string sqlCommand = "Select CustomerID, LastName, FirstName From Customers";
DbCommand dbCommand = db.GetSqlStringCommand(sqlCommand);
存储过程创建一个DbCommand
Database db = DatabaseFactory.CreateDatabase();
DbCommand dbCommand = db.GetStoredProcCommand("GetProductsByCategory");
3.管理对象
当连接对象打开后,不需要再次连接
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);
使用Using及早释放对象
Database db = DatabaseFactory.CreateDatabase();
DbCommand dbCommand = db.GetSqlStringCommand("Select Name, Address From Customers");
using (IDataReader dataReader = db.ExecuteReader(dbCommand))


{
// Process results
}
4.参数处理
Database类提供了如下的方法,用于参数的处理:
AddParameter. 传递参数给存储过程
AddInParameter. 传递输入参数给存储过程
AddOutParameter. 传递输出参数给存储过程
GetParameterValue. 得到指定参数的值
SetParameterValue. 设定参数值
使用示例如下:
Database db = DatabaseFactory.CreateDatabase();
string sqlCommand = "GetProductDetails";
DbCommand dbCommand = db.GetStoredProcCommand(sqlCommand);
db.AddInParameter(dbCommand, "ProductID", DbType.Int32, 5);
db.AddOutParameter(dbCommand, "ProductName", DbType.String, 50);
db.AddOutParameter(dbCommand, "UnitPrice", DbType.Currency, 8);
Database db = DatabaseFactory.CreateDatabase();
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);
四.使用场景
DAAB2.0是对ADO.NET2.0的补充,它允许你使用相同的数据访问代码来支持不同的数据库,您通过改变配置文件就在不同的数据库之间切换。目前虽然只提供SQLServer和Oracle的支持,但是可以通过GenericDatabase和ADO.NET 2.0下的DbProviderFactory对象来增加对其他数据库的支持。如果想要编写出来的数据库访问程序具有更好的移植性,则DAAB2.0是一个不错的选择,但是如果您想要针对特定数据库的特性进行编程,就要用ADO.NET了。
参考:Enterprise Libaray –January 2006帮助文档及QuickStart
posted @ 2006-03-14 18:08
TerryLee 阅读(19467)
评论(84) 编辑 收藏 网摘 所属分类:
[10] 模式与实践
发表评论
不错,节省了不少时间,期待Enterprise Library2.0中的其他几个Block的介绍!
3Q!
#5楼[
楼主]2006-03-15 08:25 |
@3Q
有时间其他几个我也会写的:)
TerryLee呵呵学习劲头实足,更难能可贵的是笔耕不缀,可敬!
#8楼[
楼主]2006-03-15 12:44 |
@THIN
呵呵,过奖了!
对于我这样一个单身一族来说,每天下班回家后,除了学点东西之外,也就没别的事可做了,在学习的同时,也就随手写那么一点点,作为对自己学习过程的一个记录。而现在每天能够让我感到充实的也就只有技术了:)
你的很多文章也都不错啊,《.NET中的正则表达式》我已经收藏了,有时间了我要好好学习一下~~~~~
只是将自带的QuickStart上的内容粘帖了过来.加上中文注释而已.
拜托有空写写企业库架构方面的东西.不要老把自带的入门示例往上帖.
#11楼[
楼主]2006-03-27 13:38 |
@ logFilters
关于写企业库架构方面的建议,我接受!我最近也正在做这方面的准备!
但同时我也鄙视像你这样的人!文章总共分为四部分:
1.改进的地方
2.使用示例
3.常用功能
4.使用场景
其中我在第二部分的开始写了“下面分别看一下DataAccessQuickStart中提供的一些例子”一句话,而且在最后的引用中也写了“Enterprise Libaray –January 2006帮助文档及QuickStart”。还是有你这样的人,我真是服了你了!
虽然都是DataAccessQuickStart中提供的一些例子,但是经过Terrylee重新的组织,学习起来更加容易。。。
支持!!!
#13楼[
楼主]2006-03-28 12:23 |
@喜欢雨
呵呵,谢谢~~~~
只要对大家的学习有所帮助,我就很满足了
我们也必要理会那样的大嘴巴:)
怎么接收数据库中的return返回的值啊?
例如:在数据库中建个存储过程,存储过程执行成功返回1(return回的),否则返回-1,怎么在程序中取得return值
感谢楼主,你写的很好。我的DataAccessQuickStart不能运行,请问一般怎样解决?你遇到过这样的问题吗.我的是sqlexpress2005。谢谢先。
#17楼[
楼主]2006-04-13 08:29 |
@SHILIN
您说的不能运行,不知道报什么错误?能不能把错误信息发出来看一下,这样也好解决!
感谢! 支持! 祝Terrylee 早点结束单身生活,找到好老婆!
#20楼[
楼主]2006-04-17 14:52 |
@kyoybs
谢谢你的祝福,呵呵!
关闭连接不用显式的去管理,EL会自己去做,如果你想自己管理也行,需要获取conn再自行管理!
哈哈,
最近在你看你的EnterpriseLibrary2.0系列,
写的不错,
谢谢,
期待下文,
#22楼[
楼主]2006-04-18 16:11 |
@梁广永
谢谢,写了两篇之后就再没有写
最近忙着研究Castle去了,呵呵:-)
请问,企业库支持不需要手写sqlCommand的数据更新吗?例如1.1下的commandbuilder?
#24楼[
楼主]2006-04-25 12:22 |
@SHILIN
据我所知是没有:)
我可能没说清楚我的问题,我在一个datagridview里面添加了很多新的数据,请问,怎样用Enterprise Library方便的更新数据。谢谢了。
#26楼[
楼主]2006-04-27 08:40 |
@SHILIN
EL中支持通过DataSet来更新数据,参见上面的“利用DataSet更新数据”
对于datagridview中的数据可以放在一个DataSet里面,然后统一更新!
我在使用2.0的时候,发现当一个数据集中有新增多条记录后保存,发现自动增长字段的值永远都不会和数据库中的值一样。
我想问一下,不同的数据库SQL的写法有些是不同的,那Enterprise Library怎样对不同的数据库执行不同的SQL语句呢?
{"The type initializer for 'Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ObjectBuilder.EnterpriseLibraryFactory' threw an exception."}
我做了好几个数据库连接的解决方案
只有其中的第一个可以通过
Database db = DatabaseFactory.CreateDatabase();
其它都不行,请问这是为什么?
#31楼[
楼主]2006-07-31 08:00 |
@忠实者
这不太清楚什么原因,看不到你具体的配置情况:-)
@TerryLee
谢谢!
我已经高通了
不过我还想问个问题
References中添加的是bin\*.dll吗
我改成这个就行了
#33楼[
楼主]2006-07-31 12:52 |
@忠实者
是的,添加bin目录下的
嘿嘿,不好意思,原来这里有2.0的大作,谢了!:)
楼主能不能加上点connectionString加密方面的,很期待,再次感谢!
楼主能不能加上点connectionString加密方面的,很期待,再次感谢!
#37楼[
楼主]2006-08-01 13:36 |
@TerryLee
我用Enterprise Library2.0,VS2005,.net framework2.0,sql2000做一个简单的例子:
protected void Page_Load(object sender, EventArgs e)
{
Database db = DatabaseFactory.CreateDatabase("AdventureWorks");
IDataReader reader = db.ExecuteReader(CommandType.Text, "Select EmployeeID,NationalIDNumber,LoginID from Employee");
GridView1.DataSource = reader;
GridView1.DataBind();
}
运行之后报错:
Unrecognized attribute 'requirePermission' (C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Config\machine.config line 14)
我的也是:
在这执行到
Database db = DatabaseFactory.CreateDatabase("Gtrace");
的时候出现
Unrecognized attribute 'requirePermission' (C:\WINNT\Microsoft.NET\Framework\v2.0.50727\Config\machine.config line 14)
#41楼[
楼主]2006-09-19 17:35 |
@TerryLee
如何配置连接ORALCE数据库呢
<connectionStrings>
<add name="ORACLE_CONN" connectionString="Database=DB01;Server=192.168.0.1;Integrated Security=SSPI;User ID=ABC;Password=ABC001;"
providerName="System.Data.OracleClient" />
</connectionStrings>
建立连接
Database Db = DatabaseFactory.CreateDatabase("ORACLE_CONN");
总是不成功:
Additional information: Keyword not supported: 'database'.
#43楼[
楼主]2006-10-09 22:10 |
@Tseng
配置Oracle数据的步骤差不多啊,参考我的EL Hands On Lab翻译系列练习一。
table.Rows[0]["ProductName"] = "Modified product";这句看不懂。[0]这个代表什么?谢谢!
弄清楚了,原来是第一行的意思呀。刚学.net没有一个星期,让大家见笑了。
#46楼[
楼主]2006-10-12 16:02 |
@spider[匿名]
-_-
#48楼[
楼主]2006-11-02 21:36 |
@jailu
不用客气
麻烦您,一下,如何获得新插入记录的ID呢?
还有一个上上楼提问的问题也在困扰我
怎么接收数据库中的return返回的值啊?
例如:在数据库中建个存储过程,存储过程执行成功返回1(return回的),否则返回-1,怎么在程序中取得return值
谢谢谢谢。
#50楼[
楼主]2006-11-27 17:17 |
@baiwei1977
安装完EL后有一份文档中提到了,获取存储过程的返回值
网上也有很多人写过,Google一下:)
李大哥:
我最近一直在看你写的EL系列,真写得很好,我想问下您有EL更为详尽的帮助文档的不?很多方法我都不知道怎么用,谢谢了!有的话可以发到我的邮箱:
oldong2004@163.com
@TerryLee
&
@鹏万里程
&
@请多多指教
★★★★★★★★★★★★★★★★★★★★★★★★★★
★★★★★★★★★★★★★★★★★★★★★★★★★★
Unrecognized attribute 'requirePermission' (C:\WINNT\Microsoft.NET\Framework\v2.0.50727\Config\machine.config line 14)
★★★★★★★★★★★★★★★★★★★★★★★★★★
★★★★★★★★★★★★★★★★★★★★★★★★★★
我也出现这个问题了,
请问你们是如何解决的??
谢谢!!~~
请问 ,这个Data Access Application Block跟以前的
Data Access Application BlocK中的 sqlhelper.cs 类有区别吗?
在性能上,在使用的方便性上两者有什么区别?
#55楼[
楼主]2007-02-07 16:57 |
@nbcc2001
功能上更加强大,跟其他应用程序块更好的结合
SqlHelper仅仅是一个通用的数据访问类而已
exception:<<Unrecognized attribute 'requirePermission' (C:\WINNT\Microsoft.NET\Framework\v2.0.50727\Config\machine.config line 14)
>>
这是因为你的编译环境是.net2.0的,而你所引用的enterpriseLibrary的dll却是.net1.1下编译的,所以entpriseLibrary就不明白.net2.0下的machine.config的扩展属性requirePermission了。
楼主辛苦了,问个问题啊,目前enterpriselibrary2.0支持连接的数据库只有oracle,db2,如果我还想同时连接postgre数据库,请问可以么,要自己做些什么别的连接设置么?谢谢。
请问,用EnterPriseLibrary 2.0怎样得到sqldatasource?谢谢!
查询数据时,能不能返回一行数据。在企业数据访问模块中能不能直接返回一行数据,有没有这种方法。如:database.Executexxx
我是刚入门的,请问在配置文件的connection String中不需要指明uid和pwd吗。请指教~谢谢^_^
#64楼[
楼主]2008-01-14 19:25 |
@菜鸟毛
要看你使用哪一种认证方式了,如果使用了Windows身份认证,就不用指定UserId和Password了;如果是混合模式,就需要指定。
@TerryLee
你好我想问一下我在2.0中怎么找不到
dbl.GetConnection().ConnectionString;
dbl.GetConnection().GetType().ToString()
这样的应用呢.1.1里面是有的
是我命名空间引用的不对吗
请问下楼主和各位高手,oracle 的procedure 怎么返回数据集?
如果不行的话那ExecuteDataSet对Oracle数据库就是没用的吗?
#67楼[
楼主]2008-03-10 18:15 |
@oracle
不好意思,对于Oracle的操作我不怎么熟悉:)
想请教下楼主,
我的webconfig文件:
<?xml version="1.0"?>
<configuration>
<configSections>
<section name="dataConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" />
</configSections>
<dataConfiguration defaultDatabase="DefaultConnectionString" />
<connectionStrings>
<add name="DefaultConnectionString" connectionString="Data Source=.;Initial Catalog=WebDB;UID=sa;PWD=123;"
providerName="System.Data.SqlClien" />
</connectionStrings>
<appSettings />
<system.web>
<compilation debug="true" />
<authentication mode="Windows" />
</system.web>
</configuration>
当我在运行到 DataBase database = DatabaseFactory.CreateDatabase();时就会跳出一个异常:“找不到请求的 .Net Framework 数据提供程序。可能没有安装。”,但是我用自己写的SqlConnection都可以正常执行下来,问问这个是咋原因,,是不是我的congfig有问题???谢谢
lz写这篇文章的时候我还不知道有asp.net呢。
#70楼[
楼主]2008-07-25 09:51 |
@Robot·H
:)
好象并不能解决不同数据库应用的问题吧???
比如:不同数据库SQL语句语法都不同,这个怎么解决????
很不错....谢谢LZ..谢谢博客园的一些博主..看了之后受益良多..一直默默的支持....希望有更多的好文出现...呵呵
#73楼[
楼主]2008-08-13 21:41 |
@祝兴志
使用标准的T-SQL或者存储过程应该是可以的。
#74楼[
楼主]2008-08-13 21:41 |
@Red Hat
谢谢:)