title="CreatingManagedSQLFunctionsandStoredProcedures"
description="SeehowtocreateSQLfunctionsandstoredprocedures
usingmanagedcode."/>
更新Web.sitemap文件后,花点时间在浏览器里查看,左边的菜单将包括本部分的内容.
图3:
网站地图现在包含了不部分的页面
第二步:
设置TableAdapter创建新的存储过程
我们在~/App_Code/DAL文件夹里创建一个类型化的DataSet,名称为NorthwindWithSprocs.xsd.由于我们在以前的教程里已经详细探讨了创建细节,因此我们这里一笔带过,如果你想知道详细的创建过程请参阅前面的第1章《创建一个数据访问层》在DAL文件夹上右击鼠标选“添加新项”,选DataSet模板,如图4所示.
图4:
新建一个名为NorthwindWithSprocs.xsd的数据集
这样将会创建一个新的类型化的DataSet,打开设计器,创建一个新的TableAdapter,展开TableAdapter设置向导.向导的第一步是让我们选择要连接的数据库.在下拉列表里有一个连接到Northwind数据库的连接字符串,选中它,再点下一步。
接下来的界面让我们选择TableAdapter以哪种方式访问数据库.在以前的教程里我们选择的是“UseSQLstatements”,不过在本文我们选第二项:
“Createnewstoredprocedures”,点下一步.
图5:
设置TableAdpater创建新的存储过程
接下来,我们要指定主查询(mainquery).我们将创建一个存储过程来包含SELECT查询.
使用下面的SELECT查询:
?
1
2
3
4
SELECTProductID,ProductName,SupplierID,CategoryID,
QuantityPerUnit,UnitPrice,UnitsInStock,UnitsOnOrder,
ReorderLevel,Discontinued
FROMProducts
图6:
键入SELECT查询
注意:
在名为Northwind的数据集里的ProductsTableAdapter的主查询与上面本文定义的主查询有所不同。
那个主查询还返回了每个产品的category名称和company名称.不过在后面的文章我们将对本文的TableAdapter添加这些相关的代码.再点“AdvancedOptions”按钮.我们可以指定是否让向导为TableAdapter自动生成insert,update和deletestatements;是否使用开发式并发操作(optimisticconcurrency);是否完成inserts和update操作后刷新数据表.在默认情况下,自动选中“GenerateInsert,UpdateandDeletestatements”选项。
另外,本文不用选择“Useoptimisticconcurrency”项.当选择自动创建存储过程时,“Refreshthedatatable”项将被忽略掉.不管是否选中该项,最终的insert和update存储过程都会检索刚添加或刚更新(just-insertedorjust-updatedrecord)的记录,我们将在第三步看到.
图7:
选中“GenerateInsert,UpdateandDeletestatements”项
注意:
当选中“Useoptimisticconcurrency”项的时候,向导会在WHERE语句里添加额外的条件,当其它列的值发生改动的话,将阻止数据更新.关于使用TableAdapter内置的optimisticconcurrency功能请参阅第21章《实现开放式并发》输入SELECT主查询并选取“GenerateInsert,UpdateandDeletestatements”项后,点下一步,接下来的界面,如图8所示,让我们为selecting,inserting,updating,和deleting数据的存储过程命名.将这些存储过程的名字改为Products_Select,Products_Insert,Products_Update,和Products_Delete.
图8:
为存储过程重命名
向导创建了4个存储过程,点“PreviewSQLScript”按钮,你可以在PreviewSQLScript对话框里将脚本保存在一个文件里或复制到剪贴板.
图9:
预览生成的存储过程
对存储过程重命名后,点下一步,对TableAdapter相应的方法命名.就像使用SQLstatements一样,我们可以创建方法来填充一个现有的DataTable或返回一个新的DataTable;我们也一个指定TableAdapter是否采用DB-Direct模式来插入、更新、删除记录.全选这3项,只不过将ReturnaDataTable方法重命名为GetProducts,如图10所示:
图10:
将方法重命名为Fill和GetProducts
点Next总览向导将执行的步骤.点Finish按钮完成设置.一旦向导结束后,将返回DataSet设计器,它此时将包括ProductsDataTable.
图11:
DataSet设计器将显示刚刚添加的ProductsDataTable
第三步:
考察刚刚创建的存储过程
我们在第二步里用向导创建了选择、插入、更新、删除数据的存储过程.这些存储过程可以通过VisualStudio查看或修改.打开服务器资源管理器,点到数据库的存储过程文件夹。
如图12所示,Northwind数据库包含了4个新的存储过程,Products_Delete,Products_Insert,Products_Select,andProducts_Update.
图12:
可以在StoredProcedures文件夹里找到我们创建的4个存储过程
注意:
如果你看不到服务器资源管理器,点“View”菜单,选ServerExplorer项.如果你无法找到新创建的存储过程,右击StoredProcedures文件夹,选“刷新”.
要查看或修改某个存储过程,在服务器资源管理器里双击其名字或右击该存储过程,选”打开“。
如13显示的是打开Products_Delete存储过程的画面.
图13:
可以在VisualStudio里打开并修改存储过程
Products_Delete和Products_Select存储过程的内容很好理解。
比如下面的代码构成了Products_Insert存储过程.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
ALTERPROCEDUREdbo.Products_Insert
(
@ProductNamenvarchar(40),
@SupplierIDint,
@CategoryIDint,
@QuantityPerUnitnvarchar(20),
@UnitPricemoney,
@UnitsInStocksmallint,
@UnitsOnOrdersmallint,
@ReorderLevelsmallint,
@Discontinuedbit
)
AS
SETNOCOUNTOFF;
INSERTINTO[Products]([ProductName],[SupplierID],[CategoryID],[QuantityPerUnit],
[UnitPrice],[UnitsInStock],[UnitsOnOrder],[ReorderLevel],[Discontinued])
VALUES(@ProductName,@SupplierID,@CategoryID,@QuantityPerUnit,@UnitPrice,
@UnitsInStock,@UnitsOnOrder,@ReorderLevel,@Discontinued);
SELECTProductID,ProductName,SupplierID,CategoryID,QuantityPerUnit,UnitPrice,
UnitsInStock,UnitsOnOrder,ReorderLevel,Discontinued
FROMProducts
WHERE(ProductID=SCOPE_IDENTITY())
在TableAdapter向导里定义的SELECT查询返回Products表里的列,这些列又作为存储过程的输入参数并运用到INSERTstatement中.紧接着的是一个SELECT查询,返回Products表里最新添加的记录的各列的值(包括ProductID)。
当使用BatchUpdate模式添加一个新记录时,刷新功能是很有用的。
因为它将最新添加的ProductRowinstances实例的ProductID属性赋值为数据库指派的自增值.
下面的代码说明了该功能.代码创建了基于NorthwindWithSprocs数据集的ProductsTableAdapter以及ProductsDataTable。
要向数据库添加一个新的产品,我们要创建一个ProductsRowinstance实例,对其赋值,并调用TableAdapter的Update方法,再传递给ProductsDataTable.在内部,TableAdapter的Update方法遍历传递给DataTable的所有ProductsRowinstance实例(在本例,只有一个。
因为我们只添加了一个产品),并执行相应的insert,update,或delete命令。
此时,执行Products_Insert存储过程,其向Products表添加一条新记录,并返回该记录的详细信息,然后更新ProductsRowinstance实例的ProductID值。
Update方法完成后,我们就可以通过ProductsRow的ProductID属性访问新添加记录的ProductID值了.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//CreatetheProductsTableAdapterandProductsDataTable
NorthwindWithSprocsTableAdapters.ProductsTableAdapterproductsAPI=
newNorthwindWithSprocsTableAdapters.ProductsTableAdapter();
NorthwindWithSprocs.ProductsDataTableproducts=
newNorthwindWithSprocs.ProductsDataTable();
//CreateanewProductsRowinstanceandsetitsproperties
NorthwindWithSprocs.ProductsRowproduct=products.NewProductsRow();
product.ProductName="NewProduct";
product.CategoryID=1;//Beverages
product.Discontinued=false;
//AddtheProductsRowinstancetotheDataTable
products.AddProductsRow(product);
//UpdatetheDataTableusingtheBatchUpdatepattern
productsAPI.Update(products);
//Atthispoint,wecandeterminethevalueofthenewly-addedrecord'sProductID
intnewlyAddedProductIDValue=product.ProductID;
类似的,Products_Update存储过程的UPDATEstatement后面也包含一个SELECTstatement,如下:
?
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
ALTERPROCEDUREdbo.Products_Upd