[Link] [Link][Link]
WorkingwithDatainASP.NET2.0::Creating StoredProceduresandUserDefinedFunctionswith ManagedCode Introduction
DatabaseslikeMicrosoftsSQLServer2005usetheTransactStructuredQueryLanguage(TSQL) forinserting, modifying,[Link] thatcanthenbeexecutedasasingle,[Link] Functions(UDFs),aconstructthatwewillexamineingreaterdetailinStep9. Atitscore,[Link],UPDATE,andDELETE statementsinherently applytoallrecordsinthecorrespondingtableandareonlylimitedbytheirWHERE [Link] [Link] [Link],CHARINDEX,and PATINDEX [Link] andWHILE. PriortoMicrosoftSQLServer2005,storedproceduresandUDFscouldonlybedefinedasacollectionofTSQL statements.SQLServer2005,however,wasdesignedtoprovideintegrationwiththe CommonLanguageRuntime (CLR),[Link],thestoredproceduresandUDFsinaSQL [Link],youcancreateastoredprocedureorUDFasa methodinaC#[Link] Frameworkandfromyourowncustomclasses. InthistutorialwewillexaminehowtocreatemanagedstoredproceduresandUserDefinedFunctionsandhowto [Link]! Note:[Link] [Link] objectsarelikelytobelessefficientwhenworkingwithsetsofdatathatdonotinvolvemuchprocedural [Link],checkoutthe AdvantagesofUsingManagedCodetoCreateDatabaseObjects.
Step1:MovingtheNorthwindDatabaseOutofApp_Data
AllofourtutorialsthusfarhaveusedaMicrosoftSQLServer2005ExpressEditiondatabasefileintheweb applicationsApp_Data folder.PlacingthedatabaseinApp_Data simplifieddistributingandrunningthesetutorials asallofthefileswerelocatedwithinonedirectoryandrequirednoadditionalconfigurationstepstotestthe tutorial. Forthistutorial,however,letsmovetheNorthwinddatabaseoutofApp_Data andexplicitlyregisteritwiththe [Link] databaseintheApp_Data folder,anumberofthestepsaremademuchsimplerbyexplicitlyregisteringthe databasewiththeSQLServer2005ExpressEditiondatabaseinstance. [Link] andNORTHWND_log.LDF placedina 1 of38
[Link],closeVisual [Link] andNORTHWND_log.LDF filesfromthewebsitesApp_Data foldertoafolder [Link] [Link] ServerManagementStudio.IfyouhaveanonExpressEditionofSQLServer2005installedonyourcomputer thenyoulikelyalreadyhaveManagementStudioinstalled.IfyouonlyhaveSQLServer2005ExpressEditionon yourcomputerthentakeamomenttodownloadandinstall MicrosoftSQLServerManagementStudioExpress. LaunchSQLServerManagementStudio.AsFigure1shows,ManagementStudiostartsbyaskingwhatserverto [Link] localhost\SQLExpressfortheservername,choose WindowsAuthenticationinthe Authenticationdropdownlist,andclickConnect.
Figure1:ConnecttotheAppropriateDatabaseInstance
Onceyouveconnected,theObjectExplorerwindowwilllistinformationabouttheSQLServer2005Express Editiondatabaseinstance,includingitsdatabases,securityinformation,managementoptions,andsoforth. WeneedtoattachtheNorthwinddatabaseintheDataFiles folder(orwhereveryoumayhavemovedit)tothe [Link] [Link],drill [Link] file,[Link] Figure2.
2 of38
Figure2:ConnecttotheAppropriateDatabaseInstance
Note:WhenconnectingtotheSQLServer2005ExpressEditioninstancethroughManagementStudiothe AttachDatabasesdialogboxdoesnotallowyoutodrilldownintouserprofiledirectories,suchasMy [Link],[Link] andNORTHWND_log.LDF filesinanonuser profiledirectory. [Link] [Link]
9FE54661B32FDD967F51D71D0D5145CC_LINEARTICLES\DATATUTORIALS\VOLUME3\CSHARP\73 \ASPNET_DATA_TUTORIAL_75_CS\APP_DATA\[Link]
clickingonthedatabaseandchoosingRename.
3 of38
Figure3:RenametheDatabasetoNorthwind
Step2:CreatingaNewSolutionandSQLServerProjectinVisual Studio
TocreatemanagedstoredproceduresorUDFsinSQLServer2005wewillwritethestoredprocedureandUDF logicasC#[Link],wewillneedtocompilethisclassintoanassembly ([Link] file),registertheassemblywiththeSQLServerdatabase,andthencreateastoredprocedureorUDFobject [Link] [Link],compileitfromthecommandlineusingtheC#compiler ([Link]),registeritwiththedatabaseusingtheCREATEASSEMBLY commandorfromManagementStudio,and [Link],theProfessionalandTeamSystems [Link] throughusingtheSQLServerProjecttypetocreateamanagedstoredprocedureandUDF. Note:IfyouareusingVisualWebDeveloperortheStandardeditionofVisualStudio,thenyouwillhaveto usethemanualapproachinstead.Step13providesdetailedinstructionsforperformingthesestepsmanually. IencourageyoutoreadSteps2through12beforereadingStep13sincethesestepsincludeimportantSQL ServerconfigurationinstructionsthatmustbeappliedregardlessofwhatversionofVisualStudioyouare using. [Link],chooseNewProjecttodisplaytheNewProjectdialogbox (seeFigure4).DrilldowntotheDatabaseprojecttypeandthen,fromtheTemplateslistedontheright,chooseto [Link] andplacedit withinaSolutionnamedTutorial75.
4 of38
Figure4:CreateaNewSQLServerProject
ClicktheOKbuttonintheNewProjectdialogboxtocreatetheSolutionandSQLServerProject. [Link],aftercreatingthenewSQLServerProjectwe areimmediatelyaskedtospecifythisinformation.Figure5showstheNewDatabaseReferencedialogboxthathas beenfilledouttopointtotheNorthwinddatabaseweregisteredintheSQLServer2005ExpressEditiondatabase instancebackinStep1.
5 of38
Figure5:AssociatetheSQLServerProjectwiththeNorthwindDatabase
InordertodebugthemanagedstoredproceduresandUDFswewillcreatewithinthisproject,weneedtoenable SQL/[Link] (aswedidinFigure5),VisualStudioasksusifwewanttoenableSQL/CLRdebuggingontheconnection(see Figure6).ClickYes.
6 of38
Figure6:EnableSQL/CLRDebugging
[Link] [Link],[Link] willlookatdebugginginStep12. WecannowaddnewmanagedstoredproceduresandUDFstothisproject,butbeforewedoletsfirstincludeour [Link]. BrowsetotheappropriatewebsitefolderandclickOK.AsFigure7shows,thiswillupdatetheSolutiontoinclude twoprojects:thewebsiteandtheManagedDatabaseConstructs SQLServerProject.
Figure7:TheSolutionExplorerNowIncludesTwoProjects
7 of38
TheNORTHWNDConnectionString [Link] [Link] fileinthe App_Data folder.SinceweremovedthisdatabasefromApp_Data andexplicitlyregistereditintheSQLServer 2005ExpressEditiondatabaseinstance,weneedtocorrespondinglyupdatetheNORTHWNDConnectionString [Link] fileinthewebsiteandchangetheNORTHWNDConnectionString valuesothatthe connectionstringreads:DataSource=localhost\SQLExpressInitialCatalog=NorthwindIntegrated Security=True. Afterthischange,your<connectionStrings> [Link] shouldlooksimilartothe following:
<connectionStrings> <addname="NORTHWNDConnectionString"connectionString= "DataSource=localhost\SQLExpressInitialCatalog=Northwind IntegratedSecurity=TruePooling=false" providerName="[Link]"/> </connectionStrings>
Note:Asdiscussedintheprecedingtutorial,whendebuggingaSQLServerobjectfromaclientapplication, [Link],[Link] disablesconnectionpooling(Pooling=false).Ifyoudonotplanondebuggingthemanagedstored [Link],enableconnectionpooling.
Step3:CreatingaManagedStoredProcedure
ToaddamanagedstoredproceduretotheNorthwinddatabasewefirstneedtocreatethestoredprocedureasa [Link],rightclickontheManagedDatabaseConstructs [Link],whichliststhetypes ofmanageddatabaseobjectsthatcanbeaddedtotheproject.AsFigure8shows,thisincludesstoredprocedures andUserDefinedFunctions,amongothers. [Link] [Link].
8 of38
Figure8:AddaNewStoredProcedureNamed [Link]
ThiswillcreateanewC#classfilewiththefollowingcontent:
usingSystem [Link] [Link] [Link] [Link] publicpartialclassStoredProcedures { [[Link]] publicstaticvoidGetDiscontinuedProducts() { //Putyourcodehere } }
Notethatthestoredprocedureisimplementedasastatic methodwithinapartial classfilenamed [Link],theGetDiscontinuedProducts methodisdecoratedwiththeSqlProcedure attribute,whichmarksthemethodasastoredprocedure. ThefollowingcodecreatesaSqlCommand objectandsetsitsCommandText toaSELECT query thatreturnsallofthecolumnsfromtheProducts tableforproductswhoseDiscontinued field [Link] [Link] method.
//Createthecommand SqlCommandmyCommand=newSqlCommand() [Link]= @"SELECTProductID,ProductName,SupplierID,CategoryID, QuantityPerUnit,UnitPrice,UnitsInStock,UnitsOnOrder, ReorderLevel,Discontinued FROMProducts WHEREDiscontinued=1" //Executethecommandandsendbacktheresults [Link](myCommand)
AllmanageddatabaseobjectshaveaccesstoaSqlContext objectthatrepresentsthe [Link] providesaccesstoaSqlPipe objectviaitsPipe [Link] objectisusedtoferryinformationbetweentheSQLServerdatabase [Link],theExecuteAndSend methodexecutesa passedinSqlCommand objectandsendstheresultsbacktotheclientapplication. Note:ManageddatabaseobjectsarebestsuitedforstoredproceduresandUDFsthat [Link] [Link] GetDiscontinuedProducts methodwejustcreated,however,involvesnoprocedural [Link],[Link]
9 of38
implementedasamanagedstoredproceduretodemonstratethestepsnecessaryfor creatinganddeployingmanagedstoredprocedures.
Step4:DeployingtheManagedStoredProcedure
Withthiscodecomplete,[Link] SQLServerProjectcompilesthecodeintoanassembly,registerstheassemblywiththe database,andcreatesthecorrespondingobjectsinthedatabase,linkingthemtothe [Link] [Link] [Link],deployment failswiththefollowingerror:Incorrectsyntaxnear'EXTERNAL'.Youmayneedtosetthe [Link] helpforthestoredproceduresp_dbcmptlevel. ThiserrormessageoccurswhenattemptingtoregistertheassemblywiththeNorthwind database.InordertoregisteranassemblywithaSQLServer2005database,the [Link],newSQLServer2005 [Link],databasescreatedusingMicrosoft [Link] wasinitiallyaMicrosoftSQLServer2000database,itscompatibilityleveliscurrentlysetto 80andthereforeneedstobeincreasedto90inordertoregistermanageddatabase objects. Toupdatethedatabasescompatibilitylevel,openaNewQuerywindowinManagement Studioandenter:
execsp_dbcmptlevel'Northwind',90
ClicktheExecuteiconintheToolbartoruntheabovequery.
10 of38
Figure9:UpdatetheNorthwindDatabasesCompatibilityLevel
Afterupdatingthecompatibilitylevel,[Link] deploymentshouldcompletewithouterror. ReturntoSQLServerManagementStudio,rightclickontheNorthwinddatabaseinthe ObjectExplorer,[Link],drilldownintotheProgrammabilityfolderand thenexpandtheAssembliesfolder.AsFigure10shows,theNorthwinddatabasenow includestheassemblygeneratedbytheManagedDatabaseConstructs project.
Figure10:TheManagedDatabaseConstructs AssemblyisNowRegisteredwiththe NorthwindDatabase
[Link] [Link] pointstotheGetDiscontinuedProducts methodinthe ManagedDatabaseConstructs assembly.
11 of38
WhentheGetDiscontinuedProducts storedprocedureisexecuted,it,inturn,executesthe GetDiscontinuedProducts [Link] editedthroughManagementStudio(hencethelockiconnexttothestoredprocedure name).
Figure11:TheGetDiscontinuedProducts StoredProcedureisListedintheStored ProceduresFolder
Thereisstillonemorehurdlewehavetoovercomebeforewecancallthemanagedstored procedure:[Link] byopeninganewquerywindowandexecutingtheGetDiscontinuedProducts stored [Link]:Executionofusercodein [Link]. ToexaminetheNorthwinddatabasesconfigurationinformation,enterandexecutethe 12 of38
commandexecsp_configureinthequerywindow.Thisshowsthattheclrenabled settingiscurrentlysetto0.
Figure12:TheclrenabledSettingisCurrentlySetto0
NotethateachconfigurationsettinginFigure12hasfourvalueslistedwithit:the [Link] fortheclrenabledsetting,executethefollowingcommand:
execsp_configure'clrenabled',1
Ifyoureruntheexecsp_configureyouwillseethattheabovestatementupdatedtheclr enabledsettingsconfigvalueto1,[Link] configurationchangetotakeaffectweneedtoexecutetheRECONFIGURE command,which [Link] windowandclicktheExecuteiconintheToolbar.Ifyourunexecsp_configurenowyou shouldseeavalueof1fortheclrenabledsettingsconfigandrunvalues. Withtheclrenabledconfigurationcomplete,wearereadytorunthemanaged GetDiscontinuedProducts [Link] [Link] correspondingmanagedcodeintheGetDiscontinuedProducts [Link] issuesaSELECT querytoreturnallproductsthatarediscontinuedandreturnsthisdatato thecallingapplication,whichisSQLServerManagementStudiointhisinstance. ManagementStudioreceivestheseresultsanddisplaysthemintheResultswindow.
13 of38
Figure13:TheGetDiscontinuedProducts StoredProcedureReturnsAllDiscontinued Products
Step5:CreatingManagedStoredProceduresthat AcceptInputParameters
Manyofthequeriesandstoredprocedureswehavecreatedthroughoutthesetutorials [Link],intheCreatingNewStoredProceduresfortheTyped DataSetsTableAdapterstutorialwecreatedastoredprocedurenamed GetProductsByCategoryID thatacceptedaninputparameternamed@CategoryID .Thestored procedurethenreturnedallproductswhoseCategoryID fieldmatchedthevalueofthe supplied@CategoryID parameter. Tocreateamanagedstoredprocedurethatacceptsinputparameters,simplyspecifythose [Link],letsaddanothermanagedstored proceduretotheManagedDatabaseConstructs [Link] managedstoredprocedurewillacceptaninputparameterspecifyingapriceandwillreturn allproductswhoseUnitPrice fieldislessthantheparametersvalue. Toaddanewstoredproceduretotheproject,rightclickontheManagedDatabaseConstructs [Link] [Link].AswesawinStep3,thiswillcreateanewC#classfile withamethodnamedGetProductsWithPriceLessThan placedwithinthepartial class StoredProcedures. UpdatetheGetProductsWithPriceLessThan methodsdefinitionsothatitacceptsaSqlMoney inputparameternamedprice andwritethecodetoexecuteandreturnthequeryresults:
[[Link]] publicstaticvoidGetProductsWithPriceLessThan(SqlMoneyprice) { //Createthecommand
14 of38
SqlCommandmyCommand=newSqlCommand() [Link]= @"SELECTProductID,ProductName,SupplierID,CategoryID, QuantityPerUnit,UnitPrice,UnitsInStock,UnitsOnOrder, ReorderLevel,Discontinued FROMProducts WHEREUnitPrice<@MaxPrice" [Link]("@MaxPrice",price) //Executethecommandandsendbacktheresults [Link](myCommand) }
TheGetProductsWithPriceLessThan methodsdefinitionandcodecloselyresemblesthe definitionandcodeoftheGetDiscontinuedProducts [Link] differencesarethattheGetProductsWithPriceLessThan methodacceptsasinputparameter (price),the SqlCommandsqueryincludesaparameter(@MaxPrice),andaparameterisadded totheSqlCommandsParameters collectionisandassignedthevalueoftheprice variable. Afteraddingthiscode,[Link],returntoSQLServer [Link], [Link],enterandexecutethecommandexec GetProductsWithPriceLessThan25,whichwilllistallproductslessthan$25,asFigure14 shows.
Figure14:ProductsUnder$25areDisplayed
Step6:CallingtheManagedStoredProcedurefrom theDataAccessLayer
15 of38
AtthispointwehaveaddedtheGetDiscontinuedProducts andGetProductsWithPriceLessThan managedstoredprocedurestotheManagedDatabaseConstructs projectandhaveregistered [Link] proceduresfromSQLServerManagementStudio(seeFigures13and14).Inorderforour [Link],however,weneedtoadd [Link] addtwonewmethodstotheProductsTableAdapter intheNorthwindWithSprocs TypedDataSet, whichwasinitiallycreatedintheCreatingNewStoredProceduresfortheTypedDataSets TableAdapterstutorial.InStep7wewilladdcorrespondingmethodstotheBLL. OpentheNorthwindWithSprocs TypedDataSetinVisualStudioandstartbyaddinganew methodtotheProductsTableAdapter [Link] aTableAdapter,rightclickontheTableAdaptersnameintheDesignerandchoosetheAdd Queryoptionfromthecontextmenu. Note:SincewemovedtheNorthwinddatabasefromtheApp_Data foldertotheSQL Server2005ExpressEditiondatabaseinstance,itisimperativethatthecorresponding [Link].InStep2we discussedupdatingtheNORTHWNDConnectionString [Link] makethisupdate,[Link] [Link] [Link],clickOK [Link] andupdatetheNORTHWNDConnectionString valueasdiscussed [Link] workwithouterror. AddinganewmethodlaunchestheTableAdapterQueryConfigurationwizard,whichwe [Link] TableAdaptershouldaccessthedatabase:throughanadhocSQLstatementorviaanew [Link] GetDiscontinuedProducts managedstoredprocedurewiththedatabase,choosetheUse existingstoredprocedureoptionandhitNext.
16 of38
Figure15:ChoosetheUseexistingstoredprocedureOption
[Link] GetDiscontinuedProducts managedstoredprocedurefromthedropdownlistandhitNext.
17 of38
Figure16:SelecttheGetDiscontinuedProducts ManagedStoredProcedure
Wearethenaskedtospecifywhetherthestoredprocedurereturnsrows,asinglevalue,or [Link] returnsthesetofdiscontinuedproductrows,choose thefirstoption(Tabulardata)andclickNext.
18 of38
Figure17:SelecttheTabularDataOption
Thefinalwizardscreenallowsustospecifythedataaccesspatternsusedandthenames [Link] FillByDiscontinued [Link].
19 of38
Figure18:NametheMethodsFillByDiscontinued andGetDiscontinuedProducts
RepeatthesestepstocreatemethodsnamedFillByPriceLessThan and GetProductsWithPriceLessThan intheProductsTableAdapter forthe GetProductsWithPriceLessThan managedstoredprocedure. Figure19showsascreenshotoftheDataSetDesignerafteraddingthemethodstothe ProductsTableAdapter fortheGetDiscontinuedProducts andGetProductsWithPriceLessThan managedstoredprocedures.
20 of38
Figure19:TheProductsTableAdapter IncludestheNewMethodsAddedinthisStep
Step7:AddingCorrespondingMethodstothe BusinessLogicLayer
NowthatwehaveupdatedtheDataAccessLayertoincludemethodsforcallingthe managedstoredproceduresaddedinSteps4and5,weneedtoaddcorresponding [Link] ProductsBLLWithSprocs class:
[[Link] ([Link],false)] [Link]() { [Link]() } [[Link] ([Link],false)] [Link] GetProductsWithPriceLessThan(decimalpriceLessThan) { [Link](priceLessThan)
21 of38
BothmethodssimplycallthecorrespondingDALmethodandreturntheProductsDataTable [Link] markupaboveeachmethodcausesthesemethods tobeincludedinthedropdownlistintheSELECTtaboftheObjectDataSourcesConfigure DataSourcewizard.
Step8:InvokingtheManagedStoredProceduresfrom thePresentationLayer
WiththeBusinessLogicandDataAccessLayersaugmentedtoincludesupportforcalling theGetDiscontinuedProducts andGetProductsWithPriceLessThan managedstoredprocedures, [Link]. [Link] pageintheAdvancedDAL folderand,fromthe Toolbox,[Link] propertyto DiscontinuedProducts and,fromitssmarttag,bindittoanewObjectDataSourcenamed [Link] ProductsBLLWithSprocs classsGetDiscontinuedProducts method.
Figure20:ConfiguretheObjectDataSourcetoUsetheProductsBLLWithSprocs Class
22 of38
Figure21:ChoosetheGetDiscontinuedProducts MethodfromtheDropDownListin theSELECTTab
Sincethisgridwillbeusedtojustdisplayproductinformation,setthedropdownlistsin theUPDATE,INSERT,andDELETEtabsto(None)andthenclickFinish. Uponcompletingthewizard,VisualStudiowillautomaticallyaddaBoundFieldor [Link] thesefieldsexceptforProductName andDiscontinued,atwhichpointyourGridViewand ObjectDataSourcesdeclarativemarkupshouldlooksimilartothefollowing:
<asp:GridViewID="DiscontinuedProducts"runat="server" AutoGenerateColumns="False"DataKeyNames="ProductID" DataSourceID="DiscontinuedProductsDataSource"> <Columns> <asp:BoundFieldDataField="ProductName"HeaderText="ProductName" SortExpression="ProductName"/> <asp:CheckBoxFieldDataField="Discontinued" HeaderText="Discontinued" SortExpression="Discontinued"/> </Columns> </asp:GridView> <asp:ObjectDataSourceID="DiscontinuedProductsDataSource"runat="server" OldValuesParameterFormatString="original_{0}" SelectMethod="GetDiscontinuedProducts"TypeName="ProductsBLLWithSprocs">
23 of38
</asp:ObjectDataSource>
[Link],the ObjectDataSourcecallstheProductsBLLWithSprocs classsGetDiscontinuedProducts [Link] wesawinStep7,thismethodcallsdowntotheDALsProductsDataTable classs GetDiscontinuedProducts method,whichinvokestheGetDiscontinuedProducts stored [Link] createdinStep3,returningthediscontinuedproducts. Theresultsreturnedbythemanagedstoredprocedurearepackagedupintoa ProductsDataTable bytheDALandthenreturnedtotheBLL,whichthenreturnsthemtothe [Link],the gridliststhoseproductsthathavebeendiscontinued.
Figure22:TheDiscontinuedProductsareListed
Forfurtherpractice,[Link] displaytheproductslessthantheamountenteredintotheTextBoxbycallingthe ProductsBLLWithSprocs classsGetProductsWithPriceLessThan method.
24 of38
Step9:CreatingandCallingTSQLUDFs
UserDefinedFunctions,orUDFs,aredatabaseobjectsthecloselymimicthesemanticsof [Link]#,UDFscanincludeavariable [Link] eitherscalardataastring,aninteger,[Link] lookatbothtypesofUDFs,startingwithaUDFthatreturnsascalardatatype. ThefollowingUDFcalculatestheestimatedvalueoftheinventoryforaparticularproduct. ItdoessobytakinginthreeinputparameterstheUnitPrice,UnitsInStock,and Discontinued [Link] theestimatedvalueoftheinventorybymultiplyingtheUnitPrice [Link] discontinueditems,thisvalueishalved.
CREATEFUNCTIONudf_ComputeInventoryValue ( @UnitPricemoney, @UnitsInStocksmallint, @Discontinuedbit ) RETURNSmoney AS BEGIN DECLARE@Valuedecimal SET@Value=ISNULL(@UnitPrice,0)*ISNULL(@UnitsInStock,0) IF@Discontinued=1 SET@Value=@Value*0.5 RETURN@Value END
OncethisUDFhasbeenaddedtothedatabase,itcanbefoundthroughManagement StudiobyexpandingtheProgrammabilityfolder,thenFunctions,andthenScalarvalue [Link] querylikeso:
SELECTProductID,ProductName,dbo.udf_ComputeInventoryValue (UnitPrice,UnitsInStock,Discontinued)asInventoryValue FROMProducts ORDERBYInventoryValueDESC
Ihaveaddedtheudf_ComputeInventoryValue UDFtotheNorthwinddatabaseFigure23 showstheoutputoftheaboveSELECT querywhenviewedthroughManagementStudio. AlsonotethattheUDFislistedundertheScalarvalueFunctionsfolderintheObject Explorer.
25 of38
Figure23:EachProductsInventoryValuesisListed
[Link],wecancreateaUDFthatreturnsproducts thatbelongtoaparticularcategory:
CREATEFUNCTIONdbo.udf_GetProductsByCategoryID ( @CategoryIDint ) RETURNSTABLE AS RETURN ( SELECTProductID,ProductName,SupplierID,CategoryID, QuantityPerUnit,UnitPrice,UnitsInStock,UnitsOnOrder, ReorderLevel,Discontinued FROMProducts WHERECategoryID=@CategoryID )
Theudf_GetProductsByCategoryID UDFacceptsa@CategoryID inputparameterandreturnsthe resultsofthespecifiedSELECT [Link],thisUDFcanbereferencedintheFROM (orJOIN)clauseofaSELECT [Link], ProductName,andCategoryID valuesforeachofthebeverages.
26 of38
SELECTProductID,ProductName,CategoryID FROMdbo.udf_GetProductsByCategoryID(1)
Ihaveaddedtheudf_GetProductsByCategoryID UDFtotheNorthwinddatabaseFigure24 showstheoutputoftheaboveSELECT querywhenviewedthroughManagementStudio. UDFsthatreturntabulardatacanbefoundintheObjectExplorersTablevalueFunctions folder.
Figure24:TheProductID,ProductName,andCategoryID areListedforEachBeverage
Note:FormoreinformationoncreatingandusingUDFs,checkoutIntrotoUser [Link] Functions.
Step10:CreatingaManagedUDF
Theudf_ComputeInventoryValue andudf_GetProductsByCategoryID UDFscreatedintheabove examplesareTSQLdatabaseobjects.SQLServer2005alsosupportsmanagedUDFs, whichcanbeaddedtotheManagedDatabaseConstructs projectjustlikethemanagedstored [Link],letsimplementtheudf_ComputeInventoryValue UDFinmanagedcode. ToaddamanagedUDFtotheManagedDatabaseConstructs project,rightclickontheproject 27 of38
[Link] TemplatefromtheAddNewItemdialogboxandnamethenewUDFfile udf_ComputeInventoryValue_Managed.cs.
Figure25:AddaNewManagedUDFtotheManagedDatabaseConstructs Project
TheUserDefinedFunctiontemplatecreatesapartial classnamedUserDefinedFunctions withamethodwhosenameisthesameastheclassfilesname (udf_ComputeInventoryValue_Managed,inthisinstance).Thismethodisdecoratedusingthe SqlFunction attribute,whichflagsthemethodasamanagedUDF.
usingSystem [Link] [Link] [Link] [Link] publicpartialclassUserDefinedFunctions { [[Link]] publicstaticSqlStringudf_ComputeInventoryValue_Managed() { //Putyourcodehere returnnewSqlString("Hello") } }
Theudf_ComputeInventoryValue methodcurrentlyreturnsaSqlString objectanddoesnot [Link] threeinputparametersUnitPrice,UnitsInStock,andDiscontinued andreturnsaSqlMoney
28 of38
[Link] udf_ComputeInventoryValue UDF.
[[Link]] publicstaticSqlMoneyudf_ComputeInventoryValue_Managed (SqlMoneyUnitPrice,SqlInt16UnitsInStock,SqlBooleanDiscontinued) { SqlMoneyinventoryValue=0 if(![Link]&&![Link]) { inventoryValue=UnitPrice*UnitsInStock if(Discontinued==true) inventoryValue=inventoryValue*newSqlMoney(0.5) } returninventoryValue }
NotethattheUDFmethodsinputparametersareoftheircorrespondingSQLtypes: SqlMoney fortheUnitPrice field,SqlInt16 for UnitsInStock,andSqlBoolean for Discontinued. ThesedatatypesreflectthetypesdefinedintheProducts table:theUnitPrice columnisof typemoney,theUnitsInStock columnoftypesmallint,andtheDiscontinued columnoftype bit. ThecodestartsbycreatingaSqlMoney instancenamedinventoryValue thatisassigneda [Link] tableallowsfordatabaseNULL valuesintheUnitsInPrice and UnitsInStock [Link],weneedtofirstchecktoseeifthesevaluescontainNULLs, whichwedothroughtheSqlMoney objectsIsNull [Link] and UnitsInStock containnonNULL values,thenwecomputetheinventoryValue tobetheproduct [Link],ifDiscontinued istrue,thenwehalvethevalue. Note:TheSqlMoney objectonlyallowstwoSqlMoney instancestobemultipliedtogether. ItdoesnotallowaSqlMoney instancetobemultipliedbyaliteralfloatingpoint [Link],tohalveinventoryValue wemultiplyitbyanew SqlMoney instance thathasthevalue0.5.
Step11:DeployingtheManagedUDF
NowthatthatthemanagedUDFhasbeencreated,wearereadytodeployittothe Northwinddatabase.AswesawinStep4,themanagedobjectsinaSQLServerProject aredeployedbyrightclickingontheprojectnameintheSolutionExplorerandchoosing theDeployoptionfromthecontextmenu. Onceyouhavedeployedtheproject,returntoSQLServerManagementStudioandrefresh [Link]:
l l
dbo.udf_ComputeInventoryValue theTSQLUDFcreatedinStep9,and dbo.udfComputeInventoryValue_Managed themanagedUDFcreatedinStep10thatwas
justdeployed. 29 of38
TotestthismanagedUDF,executethefollowingqueryfromwithinManagementStudio:
SELECTProductID,ProductName, dbo.udf_ComputeInventoryValue_Managed( UnitPrice, UnitsInStock, Discontinued )asInventoryValue FROMProducts ORDERBYInventoryValueDESC
ThiscommandusesthemanagedudfComputeInventoryValue_Managed UDFinsteadoftheT SQLudf_ComputeInventoryValue UDF,buttheoutputisthesame.ReferbacktoFigure23to seeascreenshotoftheUDFsoutput.
Step12:DebuggingtheManagedDatabaseObjects
IntheDebuggingStoredProcedurestutorialwediscussedthethreeoptionsfordebugging SQLServerthroughVisualStudio:DirectDatabaseDebugging,ApplicationDebugging,and [Link] DirectDatabaseDebugging,butcanbedebuggedfromaclientapplicationanddirectly [Link],however,theSQLServer 2005databasemustallowSQL/[Link] ManagedDatabaseConstructs projectVisualStudioaskeduswhetherwewantedtoenable SQL/CLRdebugging(seeFigure6inStep2).Thissettingcanbemodifiedbyrightclicking onthedatabasefromtheServerExplorerwindow.
30 of38
Figure26:EnsurethattheDatabaseAllowsSQL/CLRDebugging
ImaginethatwewantedtodebugtheGetProductsWithPriceLessThan managedstored [Link] GetProductsWithPriceLessThan method.
Figure27:SetaBreakpointintheGetProductsWithPriceLessThan Method
LetsfirstlookatdebuggingthemanageddatabaseobjectsfromtheSQLServerProject. SinceourSolutionincludestwoprojectstheManagedDatabaseConstructs SQLServerProject alongwithourwebsiteinordertodebugfromtheSQLServerProjectweneedtoinstruct VisualStudiotolaunchtheManagedDatabaseConstructs SQLServerProjectwhenwestart [Link] projectinSolutionExplorerandchoose theSetasStartUpProjectoptionfromthecontextmenu. WhentheManagedDatabaseConstructs projectislaunchedfromthedebuggeritexecutesthe [Link] file,whichislocatedintheTestScripts [Link], totesttheGetProductsWithPriceLessThan managedstoredprocedure,replacetheexisting [Link] filecontentwiththefollowingstatement,whichinvokesthe GetProductsWithPriceLessThan managedstoredprocedurepassinginthe@CategoryID value of14.95:
execGetProductsWithPriceLessThan14.95
[Link],startdebuggingbygoingtotheDebug menuandchoosingStartDebuggingorbyhittingF5orthegreenplayiconintheToolbar. ThiswillbuildtheprojectswithintheSolution,deploythemanageddatabaseobjectstothe Northwinddatabase,[Link] [Link],thebreakpointwill
31 of38
behitandwecanstepthroughtheGetProductsWithPriceLessThan method,examinethe valuesoftheinputparameters,andsoon.
Figure28:TheBreakpointintheGetProductsWithPriceLessThan MethodWasHit
InorderforaSQLdatabaseobjecttobedebuggedthroughaclientapplication,itis [Link] thedatabaseinServerExplorerandensurethattheApplicationDebuggingoptionis [Link],[Link] [Link] Step2oftheDebuggingStoredProcedurestutorial. [Link],[Link] [Link] managedobjectsthathasabreakpoint,theapplicationwillhaltandcontrolwillbeturned overtothedebugger,whereyoucanstepthroughthecodeasshowninFigure28.
Step13:ManuallyCompilingandDeployingManaged DatabaseObjects
SQLServerProjectsmakeiteasytocreate,compile,anddeploymanageddatabase [Link],SQLServerProjectsareonlyavailableintheProfessionalandTeam
32 of38
[Link] EditionofVisualStudioandwanttousemanageddatabaseobjects,youwillneedto [Link]: 1. 2. 3. 4. Createafilethatcontainsthesourcecodeforthemanageddatabaseobject, Compiletheobjectintoanassembly, RegistertheassemblywiththeSQLServer2005database,and CreateadatabaseobjectinSQLServerthatpointstotheappropriatemethodinthe assembly.
Toillustratethesetasks,letscreateanewmanagedstoredprocedurethatreturnsthose productswhoseUnitPrice [Link] [Link] andenterthefollowingcodeintothe file(youcanuseVisualStudio,Notepad,oranytexteditortoaccomplishthis):
usingSystem [Link] [Link] [Link] [Link] publicpartialclassStoredProcedures { [[Link]] publicstaticvoidGetProductsWithPriceGreaterThan(SqlMoneyprice) { //Createthecommand SqlCommandmyCommand=newSqlCommand() [Link]= @"SELECTProductID,ProductName,SupplierID,CategoryID, QuantityPerUnit,UnitPrice,UnitsInStock,UnitsOnOrder, ReorderLevel,Discontinued FROMProducts WHEREUnitPrice>@MinPrice" [Link]("@MinPrice",price) //Executethecommandandsendbacktheresults [Link](myCommand) } }
ThiscodeisnearlyidenticaltothatoftheGetProductsWithPriceLessThan methodcreatedin [Link],theWHERE clause,andtheparameter [Link] method,theWHERE clause read:WHEREUnitPrice<@[Link],inGetProductsWithPriceGreaterThan,weuse:WHERE UnitPrice>@MinPrice. [Link],navigateto [Link] fileandusetheC# compiler([Link])tocompiletheclassfileintoanassembly:
[Link]/t:library/out:[Link]
33 of38
[Link] innotinthesystemsPATH,youwillhavetofullyreference itspath,%WINDOWS%\[Link]\Framework\version\,likeso:
C:\WINDOWS\[Link]\Framework\v2.0.50727\[Link]/t:library/out:ManuallyCreatedDBObjects
Figure29:[Link] IntoanAssembly
The/t flagspecifiesthattheC#classfileshouldbecompiledintoaDLL(ratherthanan executable).The/out flagspecifiesthenameoftheresultingassembly. Note:[Link] classfilefromthe commandlineyoucouldalternativelyuseVisualC#ExpressEditionorcreatea [Link] haskindlyprovidedsuchaVisualC#ExpressEditionprojectwithcodeforthe GetProductsWithPriceGreaterThan storedprocedureandthetwomanagedstored proceduresandUDFcreatedinSteps3,5,[Link] SQLcommandsneededtoaddthecorrespondingdatabaseobjects. Withthecodecompiledintoanassembly,wearereadytoregistertheassemblywithinthe [Link],usingthecommand CREATEASSEMBLY,[Link] ManagementStudio. FromManagementStudio,expandtheProgrammabilityfolderintheNorthwinddatabase. [Link],right [Link] displaystheNewAssemblydialogbox(seeFigure30).ClickontheBrowsebutton,select [Link] assemblywejustcompiled,andthenclickOKtoaddthe [Link] assemblyin theObjectExplorer.
34 of38
Figure30:[Link] AssemblytotheDatabase
35 of38
Figure31:[Link] isListedintheObjectExplorer
WhilewehaveaddedtheassemblytotheNorthwinddatabase,wehaveyettoassociatea storedprocedurewiththeGetProductsWithPriceGreaterThan [Link] accomplishthis,openanewquerywindowandexecutethefollowingscript:
CREATEPROCEDURE[dbo].[GetProductsWithPriceGreaterThan] ( @price[numeric](18,0) ) WITHEXECUTEASCALLER AS EXTERNALNAME[ManuallyCreatedDBObjects].[StoredProcedures].[GetProductsWithPriceGreaterThan] GO
ThiscreatesanewstoredprocedureintheNorthwinddatabasenamed GetProductsWithPriceGreaterThan andassociatesitwiththemanagedmethod GetProductsWithPriceGreaterThan (whichisintheclassStoredProcedures ,whichisinthe assemblyManuallyCreatedDBObjects). Afterexecutingtheabovescript,refreshtheStoredProceduresfolderintheObject [Link] [Link],enterandexecutethe followingscriptinthequerywindow:
36 of38
execGetProductsWithPriceGreaterThan24.95
AsFigure32shows,theabovecommanddisplaysinformationforthoseproductswitha UnitPrice greaterthan$24.95.
Figure32:[Link] isListedintheObjectExplorer
Summary
MicrosoftSQLServer2005providesintegrationwiththeCommonLanguageRuntime (CLR),[Link],these databaseobjectscouldonlybecreatedusingTSQL,butnowwecancreatetheseobjects [Link]#.Inthistutorialwecreatedtwomanaged storedproceduresandamanagedUserDefinedFunction. VisualStudiosSQLServerProjecttypefacilitatescreating,compiling,anddeploying [Link],[Link],SQL ServerProjecttypesareonlyavailableintheProfessionalandTeamSystemseditionsof [Link] Studio,thecreation,compilation,anddeploymentstepsmustbeperformedmanually,as wesawinStep13. HappyProgramming!
FurtherReading
37 of38
Formoreinformationonthetopicsdiscussedinthistutorial,refertothefollowing resources:
l l l l l l l l l l
AdvantagesandDrawbacksofUserDefinedFunctions CreatingSQLServer2005ObjectsinManagedCode CreatingTriggersUsingManagedCodeinSQLServer2005 HowTo:CreateandRunaCLRSQLServerStoredProcedure HowTo:CreateandRunaCLRSQLServerUserDefinedFunction HowTo:[Link] ScripttoRunSQLObjects IntrotoUserDefinedFunctions ManagedCodeandSQLServer2005(Video) TransactSQLReference Walkthrough:CreatingaStoredProcedureinManagedCode
AbouttheAuthor
ScottMitchell,authorofsevenASP/[Link], [Link] independentconsultant,trainer,[Link] [Link]@[Link] blog,whichcanbefoundat[Link]
SpecialThanksTo
[Link] [Link],Srenalsocreatedthe VisualC#ExpressEditionprojectincludedinthisarticlesdownloadformanuallycompiling [Link]?Ifso, dropmealineatmitchell@[Link].
38 of38