您的位置:首页 > 其它

Designing Data Tier Components and Passing Data Through Tiers

2004-09-06 10:21 573 查看

DesigningDataTierComponentsandPassingDataThroughTiers

RelatedLinks
patternsandpracticesIndex
.NETArchitectureCenter
ApplicationArchitecturefor.NET:DesigningApplicationsandServices
AngelaCrocker,AndyOlsen,andEdwardJezierski
MicrosoftCorporation
August2002
Appliesto:
Microsoft®.NETapplications
Summary:LearnhowtobestexposeyourdatatoMicrosoft.NETapplicationsandhowtoimplementaneffectivestrategyforpassingdatabetweenthetiersinadistributedapplication.(65printedpages)

Download

DownloadDesigningDataTierComponentsandPassingDataThroughTiersin.pdfformat.

Contents

Introduction
MappingRelationalDatatoBusinessEntities
ImplementingDataAccessLogicComponents
ImplementingBusinessEntities
Transactions
Validations
ExceptionManagement
AuthorizationandSecurity
Deployment
Appendix
Collaborators

Introduction

Whendesigningadistributedapplication,youneedtodecidehowtoaccessandrepresentthebusinessdataassociatedwithyourapplication.Thisdocumentprovidesguidancetohelpyouchoosethemostappropriatewayofexposing,persistingandpassingthatdatathroughthetiersofanapplication.
Figure1depictsthecommontiersofadistributedapplication.Thisdocumentdistinguishesbetweenbusinessdataandthebusinessprocessesthatusethedata;thebusinessprocesstierisdiscussedonlywhereneededforclarification.Likewise,thepresentationtierisdiscussedonlywheretherearedirectimplicationsforthewaydataisrepresented,suchasthewayMicrosoft®ASP.NETWebpagesexposebusinessdata.Figure1introducestwonewterms:dataaccesslogiccomponentsandbusinessentitycomponents.Thesetermsaredescribedlaterinthisdocument.

Figure1.Accessingandrepresentingdatainadistributedapplication
Mostapplicationsstoredatainrelationaldatabases.Whilethereareotheroptionsforstoringdata,thisdocumentfocusesonhow.NETapplicationsinteractwithrelationaldatabases,anddoesnotspecificallydiscusshowtointeractwithdataheldinotherdatastoressuchasflatfilesornon-relationaldatabases.
Thisdocumentmakesacleardistinctionbetweenpersistencelogicandthedataitself.Thereasonsforseparatingpersistencelogicfromthedataincludethefollowing:
·Separatedatapersistencecomponentscanisolatetheapplicationfromdatabasedependencies,suchasthenameofthedatasource,connectioninformationandfieldnames.
·Manyoftoday'sapplicationsuselooselycoupled,message-basedtechnologies,suchasXMLWebservicesandMicrosoftMessageQueuing(alsoknownasMSMQ).Theseapplicationstypicallycommunicatebypassingbusinessdocuments,ratherthanbypassingobjects.
NoteForanintroductiontoXMLWebservices,seethearticletitled.NETWebServices:WebMethodsMakeitEasytoPublishYourApp'sInterfaceovertheInternetintheMarch2002issueofMSDN®Magazine.FormoreinformationaboutMessageQueuing,seeMessageQueuingOverview.
Toattainthedistinctionbetweenpersistencelogicandthedataitself,thisdocumentproposestwodifferentcomponenttypes.
·Dataaccesslogiccomponents.Dataaccesslogiccomponentsretrievedatafromthedatabaseandsaveentitydatabacktothedatabase.Dataaccesslogiccomponentsalsocontainanybusinesslogicneededtoachievedata-relatedoperations.
·Businessentitycomponents.Dataisusedtorepresentrealworldbusinessentities,suchasproductsororders.Therearenumerouswaystorepresentthesebusinessentitiesinyourapplication—forexample,XMLorDataSetsorcustomobject-orientedclasses—dependingonthephysicalandlogicaldesignconstraintsoftheapplication.Designoptionsareinvestigatedindetaillaterinthisdocument.

DataAccessLogicComponents

ADataAccessLogicComponentprovidesmethodstoperformthefollowingtasksuponadatabase,onbehalfofthecaller:
·Createrecordsinthedatabase
·Readrecordsinthedatabase,andreturnbusinessentitydatatothecaller
·Updaterecordsinthedatabase,byusingrevisedbusinessentitydatasuppliedbythecaller
·Deleterecordsinthedatabase
Themethodsthatperformtheprecedingtasksareoftencalled"CRUD"methods,whereCRUDisanacronymbasedonthefirstletterofeachtask.
TheDataAccessLogicComponentalsohasmethodstoimplementbusinesslogicagainstthedatabase.Forexample,aDataAccessLogicComponentmighthaveamethodtofindthehighest-sellingproductinacatalogforthismonth.
Typically,aDataAccessLogicComponentaccessesasingledatabaseandencapsulatesthedata-relatedoperationsforasingletableoragroupofrelatedtablesinthedatabase.Forexample,youmightdefineoneDataAccessLogicComponenttodealwiththeCustomerandAddresstablesinadatabase,andanotherDataAccessLogicComponenttodealwiththeOrdersandOrderDetailstables.Thedesigndecisionsformappingdataaccesslogiccomponentstodatabasetablesarediscussedlaterinthisdocument.

RepresentingBusinessEntities

EachDataAccessLogicComponentdealswithaspecifictypeofbusinessentity.Forexample,theCustomerDataAccessLogicComponentdealswithCustomerbusinessentities.Therearemanydifferentwaystorepresentbusinessentities,dependingonfactorssuchasthefollowing:
·DoyouneedtobindbusinessentitydatatocontrolsinaMicrosoftWindows®formoronanASP.NETpage?
·Doyouneedtoperformsortingorsearchingoperationsonthebusinessentitydata?
·Doesyourapplicationdealwithbusinessentitiesoneatatime,ordoesittypicallydealwithsetsofbusinessentities?
·Willyoudeployyourapplicationlocallyorremotely?
·WillthebusinessentitybeusedbyXMLWebservices?
·Howimportantarenonfunctionalrequirements,suchasperformance,scalability,maintainability,andprogrammingconvenience?
Thisdocumentoutlinestheadvantagesanddisadvantagesofthefollowingimplementationoptions:
·XML.YouuseanXMLstringoranXMLDocumentObjectModel(DOM)objecttorepresentbusinessentitydata.XMLisanopenandflexibledatarepresentationformatthatcanbeusedtointegratediversetypesofapplications.
·DataSet.ADataSetisanin-memorycacheoftables,obtainedfromarelationaldatabaseoranXMLdocument.ADataAccessLogicComponentcanuseaDataSettorepresentbusinessentitydataretrievedfromthedatabase,andyoucanusetheDataSetinyourapplication.ForanintroductiontoDataSets,see"IntroducingADO.NET"inthe.NETDataAccessArchitectureGuide.
·TypedDataSet.AtypedDataSetisaclassthatinheritsfromtheADO.NETDataSetclassandprovidesstronglytypedmethods,eventsandpropertiestoaccessthetablesandcolumnsinaDataSet.
·BusinessEntityComponent.Thisisacustomclasstorepresenteachtypeofbusinessentity.Youdefinefieldstoholdthebusinessentitydata,andyoudefinepropertiestoexposethisdatatotheclientapplication.Youdefinemethodstoencapsulatesimplebusinesslogic,makinguseofthefieldsdefinedintheclass.ThisoptiondoesnotimplementCRUDmethodsaspass-throughmethodstotheunderlyingDataAccessLogicComponent;theclientapplicationcommunicatesdirectlywiththeDataAccessLogicComponenttoperformCRUDoperations.
·BusinessEntityComponentwithCRUDbehaviors.Youdefineacustomentityclassasdescribedpreviously,andyouimplementtheCRUDmethodsthatcalltheunderlyingDataAccessLogicComponentassociatedwiththisbusinessentity.
NoteIfyouprefertoworkwithyourdatainamoreobject-orientedfashion,youcanusethealternateapproachofdefininganobjectpersistencelayerbasedonthereflectioncapabilitiesofthecommonlanguageruntime.Youcancreateaframeworkthatusesreflectiontoreadthepropertiesoftheobjectsanduseamappingfiletodescribethemappingbetweenobjectsandtables.However,toimplementthiseffectivelywouldconstituteamajorinvestmentininfrastructurecode.ThisoutlaymightbeviableforISVsandsolutionproviders,butnotforthemajorityoforganizations,anditisbeyondthescopeofthisdocument.

TechnicalConsiderations

Figure2showssomeofthetechnicalconsiderationsthatinfluencetheimplementationstrategyfordataaccesslogiccomponentsandbusinessentities.Thisdocumentaddresseseachofthesetechnicalconsiderationsandprovidesrecommendations.

Figure2.Technicalconsiderationsthatinfluencethedesignofdataaccesslogiccomponentsandbusinessentities

MappingRelationalDatatoBusinessEntities

Databasestypicallycontainmanytables,withrelationshipsimplementedbyprimarykeysandforeignkeysinthesetables.Whenyoudefinebusinessentitiestorepresentthisdatainyour.NETapplication,youmustdecidehowtomapthesetablestobusinessentities.
Considerthehypotheticalretailer'sdatabaseshowninFigure3.

Figure3.Hypotheticaltablerelationshipsinarelationaldatabase
Thefollowingtablesummarizesthetypesofrelationshipsintheexampledatabase.
TypeofrelationshipExampleDescription
One-to-manyCustomer:Address

Customer:Order
Acustomercanhavemanyaddresses,suchasadeliveryaddress,abillingaddress,andacontactaddress.

Acustomercanplaceseveralorders.
Many-to-manyOrder:ProductAnordercancomprisemanyproducts;eachproductisrepresentedbyaseparaterowintheOrderDetailstable.Likewise,aproductcanbefeaturedinmanyorders.
Whenyoudefinebusinessentitiestomodeltheinformationinthedatabase,considerhowyouwillusetheinformationinyourapplication.Identifythecorebusinessentitiesthatencapsulateyourapplication'sfunctionality,ratherthandefiningaseparatebusinessentityforeachtable.
Typicaloperationsinthehypotheticalretailer'sapplicationareasfollows:
·Get(orupdate)informationaboutacustomer,includinghisorheraddresses
·Getalistofordersforacustomer
·Getalistoforderitemsforaparticularorder
·Placeaneworder
·Get(orupdate)informationaboutaproductoracollectionofproducts
Tofulfilltheseapplicationrequirements,therearethreelogicalbusinessentitiesthattheapplicationwillhandle:aCustomer,anOrderandaProduct.Foreachbusinessentity,aseparateDataAccessLogicComponentwillbedefinedasfollows:
·CustomerDataAccessLogicComponent.ThisclasswillprovideservicestoretrieveandmodifydataintheCustomerandAddresstables.
·OrderDataAccessLogicComponent.ThisclasswillprovideservicestoretrieveandmodifydataintheOrderandOrderDetailstables.
·ProductDataAccessLogicComponent.ThisclasswillprovideservicestoretrieveandmodifydataintheProducttable.
Figure4illustratestherelationshipsbetweenthedataaccesslogiccomponentsandthetablesthattheyrepresentinthedatabase.

Figure4.Definingdataaccesslogiccomponentstoexposerelationaldatato.NETapplications
Foradescriptionofhowtoimplementdataaccesslogiccomponents,seeImplementingDataAccessLogicComponentslaterinthisdocument.

RecommendationsforMappingRelationalDatatoBusinessEntities

Tomaprelationaldatatobusinessentities,considerthefollowingrecommendations:
·Takethetimetoanalyzeandmodelthelogicalbusinessentitiesofyourapplication,ratherthandefiningaseparatebusinessentityforeverytable.OneofthewaystomodelhowyourapplicationworksistouseUnifiedModelingLanguage(UML).UMLisaformaldesignnotationformodelingobjectsinanobject-orientedapplication,andforcapturinginformationabouthowobjectsrepresentautomatedprocesses,humaninteractions,andassociations.Formoreinformation,seeModelingYourApplicationandData.
·Donotdefineseparatebusinessentitiestorepresentmany-to-manytablesinthedatabase;theserelationshipscanbeexposedthroughmethodsimplementedinyourDataAccessLogicComponent.Forexample,theOrderDetailstableintheprecedingexampleisnotmappedtoaseparatebusinessentity;instead,theOrdersdataaccesslogiccomponentencapsulatestheOrderDetailstabletoachievethemany-to-manyrelationshipbetweentheOrderandProducttables.
·Ifyouhavemethodsthatreturnaparticulartypeofbusinessentity,placethesemethodsintheDataAccessLogicComponentforthattype.Forexample,ifyouareretrievingallordersforacustomer,implementthatfunctionintheOrderDataAccessLogicComponentbecauseyourreturnvalueisofthetypeOrder.Conversely,ifyouareretrievingallcustomersthathaveorderedaspecificproduct,implementthatfunctionintheCustomerDataAccessLogicComponent.
·Dataaccesslogiccomponentstypicallyaccessdatafromasingledatasource.Ifaggregationfrommultipledatasourcesisrequired,itisrecommendedtodefineaseparateDataAccessLogicComponenttoaccesseachdatasourcethatcanbecalledfromahigher-levelbusinessprocesscomponentthatcanperformtheaggregation.Therearetworeasonsforthisrecommendation:
·TransactionmanagementiscentralizedtothebusinessprocesscomponentanddoesnotneedtobecontrolledexplicitlybytheDataAccessLogicComponent.IfyouaccessmultipledatasourcesfromoneDataAccessLogicComponent,youwillneedtheDataAccessLogicComponenttobetherootoftransactions,whichwillintroduceadditionaloverheadonfunctionswhereyouareonlyreadingdata.
·Aggregationisusuallynotarequirementinallareasoftheapplication,andbyseparatingtheaccesstothedata,youcanletthetypestandaloneaswellasbepartofanaggregationwhenneeded.

ImplementingDataAccessLogicComponents

ADataAccessLogicComponentisastatelessclass,meaningthatallmessagesexchangedcanbeinterpretedindependently.Nostateisheldbetweencalls.TheDataAccessLogicComponentprovidesmethodsforaccessingoneormorerelatedtablesinasingledatabase,orinsomeinstances,multipledatabasesasinthecaseofhorizontaldatabasepartitioning.Typically,themethodsinaDataAccessLogicComponentinvokestoredprocedurestoperformtheiroperations.
Oneofthekeygoalsofdataaccesslogiccomponentsistohidetheinvocationandformatidiosyncrasiesofthedatabasefromthecallingapplication.Dataaccesslogiccomponentsprovideanencapsulateddata-accessservicetotheseapplications.Specifically,dataaccesslogiccomponentshandlethefollowingimplementationdetails:
·Manageandencapsulatelockingschemes
·Handlesecurityandauthorizationissuesappropriately
·Handletransactionissuesappropriately
·Performdatapaging
·Performdata-dependentroutingifrequired
·Implementacachingstrategyifappropriate,forqueriesofnontransactionaldata
·Performdatastreaminganddataserialization
Someoftheseissuesareexploredinmoredetaillaterinthissection.

ApplicationScenariosforDataAccessLogicComponents

Figure5showshowaDataAccessLogicComponentcanbecalledfromavarietyofapplicationtypes,includingWindowsFormsapplications,ASP.NETapplications,XMLWebservicesandbusinessprocesses.Thesecallsmightbelocalorremote,dependingonhowyoudeployyourapplications.

Figure5.Applicationscenariosfordataaccesslogiccomponents(clickthumbnailforlargerimage)

ImplementingDataAccessLogicComponentClasses

DataaccesslogiccomponentsuseADO.NETtoexecuteSQLstatementsorcallstoredprocedures.ForanexampleofaDataAccessLogicComponentclass,seeHowtoDefineaDataAccessLogicComponentClassintheappendix.
Ifyourapplicationcontainsmultipledataaccesslogiccomponents,youcansimplifytheimplementationofDataAccessLogicComponentclassesbyusingadataaccesshelpercomponent.Thiscomponentcanhelpmanagedatabaseconnections,executeSQLcommandsandcacheparameters.Thedataaccesslogiccomponentsstillencapsulatethelogicrequiredtoaccessthespecificbusinessdata,whereasthedataaccesshelpercomponentcentralizesdataaccessAPIdevelopmentanddataconnectionconfiguration,therebyhelpingtoreducecodeduplication.MicrosoftprovidestheDataAccessApplicationBlockfor.NET,whichcanbeusedasagenericdataaccesshelpercomponentinyourapplicationswhenyouuseMicrosoftSQLServer™databases.Figure6showshowtousethedataaccesshelpercomponenttohelpimplementdataaccesslogiccomponents.

Figure6.Implementingdataaccesslogiccomponentsbyusingthedataaccesshelpercomponent
Ifthereareutilityfunctionsthatarecommontoallofyourdataaccesslogiccomponents,youcandefineabaseclassfordataaccesslogiccomponentstoinheritfromandextend.
DesignyourDataAccessLogicComponentclassestoprovideaconsistentinterfacefordifferenttypesofclients.IfyoudesigntheDataAccessLogicComponenttobecompatiblewiththerequirementsofyourcurrentandpotentialbusinessprocesstierimplementation,youcanreducethenumberofadditionalinterfaces,facadesormappinglayersthatyoumustimplement.
Tosupportadiverserangeofbusinessprocessesandapplications,considerthefollowingtechniquestopassdatatoandfromDataAccessLogicComponentmethods:
·PassingbusinessentitydataintomethodsintheDataAccessLogicComponent.Youcanpassthedatainseveraldifferentformats:asaseriesofscalarvalues,asanXMLstring,asaDataSetorasacustomBusinessEntityComponent.
·ReturningbusinessentitydatafrommethodsintheDataAccessLogicComponent.Youcanreturnthedatainseveraldifferentformats:asoutput-parameterscalarvalues,asanXMLstring,asaDataSet,asacustomBusinessEntityComponentorasadatareader.
Thefollowingsectionspresenttheoptionsforpassingbusinessentitydatatoandfromyourdataaccesslogiccomponents,inadditiontotheadvantagesanddisadvantagesofeachapproach.Thisinformationwillhelpyoutomakeaninformedchoicebasedonyourspecificapplicationscenario.

PassingScalarValuesAsInputsandOutputs

Theadvantagesofthisoptionareasfollows:
·Abstraction.Callersmustknowaboutonlythedatathatdefinesthebusinessentity,butnotaspecifictypeorthespecificstructureofthebusinessentity.
·Serialization.Scalarvaluesnativelysupportserialization.
·Efficientuseofmemory.Scalarvaluesonlyconveythedatathatisactuallyneeded.
·Performance.Whendealingwithinstancedata,scalarvaluesofferbetterperformancethantheotheroptionsdescribedinthisdocument.
Thedisadvantagesofthisoptionareasfollows:
·Tightcouplingandmaintenance.Schemachangescouldrequiremethodsignaturestobemodified,whichwillaffectthecallingcode.
·Collectionsofentities.TosaveorupdatemultipleentitiestoaDataAccessLogicComponent,youmustmakeseparatemethodcalls.Thiscanbeasignificantperformancehitindistributedenvironments.
·Supportofoptimisticconcurrency.Tosupportoptimisticconcurrency,timestampcolumnsmustbedefinedinthedatabaseandincludedaspartofthedata.

PassingXMLStringsAsInputsandOutputs

Theadvantagesofthisoptionareasfollows:
·Loosecoupling.Callersmustknowaboutonlythedatathatdefinesthebusinessentityandtheschemathatprovidesmetadataforthebusinessentity.
·Integration.AcceptingXMLwillsupportcallersimplementedinvariousways—forexample,.NETapplications,BizTalkOrchestrationrules,andthird-partybusinessrulesengines.
·Collectionsofbusinessentities.AnXMLstringcancontaindataformultiplebusinessentities.
·Serialization.Stringsnativelysupportserialization.
Thedisadvantagesofthisoptionareasfollows:
·ReparsingeffortforXMLstrings.TheXMLstringmustbereparsedatthereceivingend.VerylargeXMLstringsincuraperformanceoverhead.
·Inefficientuseofmemory.XMLstringscanbeverbose,whichcancauseinefficientuseofmemoryifyouneedtopasslargeamountsofdata.
·Supportingoptimisticconcurrency.Tosupportoptimisticconcurrency,timestampcolumnsmustbedefinedinthedatabaseandincludedaspartoftheXMLdata.

PassingDataSetsAsInputsandOutputs

Theadvantagesofthisoptionareasfollows:
·Nativefunctionality.DataSetsprovidebuilt-infunctionalitytohandleoptimisticconcurrency(alongwithdataadapters)andsupportforcomplexdatastructures.Furthermore,typedDataSetsprovidesupportfordatavalidation.
·Collectionsofbusinessentities.DataSetsaredesignedtohandlesetsandcomplexrelationships,soyoudonotneedtowritecustomcodetoimplementthisfunctionality.
·Maintenance.Schemachangesdonotaffectthemethodsignatures.However,ifyouareusingtypedDataSetsandtheassemblyhasastrongname,theDataAccessLogicComponentclassmustberecompiledagainstthenewversion,mustuseapublisherpolicyinsidetheglobalassemblycache,ormustdefinea<bindingRedirect>elementinitsconfigurationfile.Forinformationabouthowtheruntimelocatesassemblies,seeHowtheRuntimeLocatesAssemblies.
·Serialization.ADataSetsupportsXMLserializationnativelyandcanbeserializedacrosstiers.
Thedisadvantagesofthisoptionareasfollows:
·Performance.InstantiatingandmarshallingDataSetsincuraruntimeoverhead.
·Representationofasinglebusinessentity.DataSetsaredesignedtohandlesetsofdata.Ifyourapplicationworksmainlywithinstancedata,scalarvaluesorcustomentitiesareabetterapproachasyouwillnotincurtheperformanceoverhead.

PassingCustomBusinessEntityComponentsAsInputsandOutputs

Theadvantagesofthisoptionareasfollows:
·Maintenance.SchemachangesmaynotaffecttheDataAccessLogicComponentmethodsignatures.However,thesameissuesariseaswithtypedDataSetsiftheBusinessEntityComponentisheldinastrong-namedassembly.
·Collectionsofbusinessentities.Anarrayoracollectionofcustombusinessentitycomponentscanbepassedtoandfromthemethods.
Thedisadvantagesofthisoptionareasfollows:
·Supportingoptimisticconcurrency.Tosupportoptimisticconcurrencyeasily,timestampcolumnsmustbedefinedinthedatabaseandincludedaspartoftheinstancedata.
·Limitedintegration.WhenusingcustombusinessentitycomponentsasinputstotheDataAccessLogicComponent,thecallermustknowthetypeofbusinessentity;thiscanlimitintegrationforcallersthatarenotusing.NET.However,thisissuedoesnotnecessarilylimitintegrationifthecallerusescustombusinessentitycomponentsasoutputfromtheDataAccessLogicComponent.Forexample,aWebmethodcanreturnthecustomBusinessEntityComponentthatwasreturnedfromaDataAccessLogicComponent,andtheBusinessEntityComponentwillbeserializedtoXMLautomaticallyusingXMLserialization.

ReturningDataReadersAsOutputs

Theadvantageofthisoptionisasfollows:
·Performance.ThereisaperformancebenefitwhenyouneedtorenderdataquicklyandyoucandeployyourDataAccessLogicComponentwiththepresentationtiercode.
Thedisadvantageofthisoptionisasfollows:
·Remoting.Itisinadvisabletousedatareadersinremotingscenarios,becauseofthepotentialforclientapplicationstoholdthedatabaseconnectionopenforlengthyperiods.

UsingStoredProceduresinConjunctionwithDataAccessLogicComponents

Youcanusestoredprocedurestoperformmanyofthedataaccesstaskssupportedbydataaccesslogiccomponents.
Advantages
·Storedproceduresgenerallyresultinimprovedperformance,becausethedatabasecanoptimizethedataaccessplanusedbytheprocedureandcachetheplanforsubsequentreuse.
·Storedprocedurescanbeindividuallysecuredwithinthedatabase.Anadministratorcangrantclientspermissiontoexecuteastoredprocedure,withoutgrantinganypermissionsontheunderlyingtables.
·Storedproceduresmayresultineasiermaintenance,becauseitisgenerallyeasiertomodifyastoredprocedurethantochangeahard-codedSQLstatementwithinadeployedcomponent.However,thebenefitdecreasesasthebusinesslogicimplementedinthestoredproceduresincreases.
·Storedproceduresaddanextralevelofabstractionfromtheunderlyingdatabaseschema.Theclientofthestoredprocedureisisolatedfromtheimplementationdetailsofthestoredprocedureandfromtheunderlyingschema.
·Storedprocedurescanreducenetworktraffic.SQLstatementscanbeexecutedinbatches,ratherthantheapplicationhavingtosendmultipleSQLrequests.
Despitetheadvantageslistedabove,therearesomesituationswheretheuseofstoredproceduresisnotrecommendedormaybeinfeasible.
Disadvantages
·Applicationsthatinvolveextensivebusinesslogicandprocessingcouldplaceanexcessiveloadontheserverifthelogicwasimplementedentirelyinstoredprocedures.Examplesofthistypeofprocessingincludedatatransfers,datatraversals,datatransformationsandintensivecomputationaloperations.Youshouldmovethistypeofprocessingtobusinessprocessordataaccesslogiccomponents,whichareamorescalableresourcethanyourdatabaseserver.
·Donotputallofyourbusinesslogicintostoredprocedures.MaintenanceandtheagilityofyourapplicationbecomesanissuewhenyoumustmodifybusinesslogicinT-SQL.Forexample,ISVapplicationsthatsupportmultipleRDBMSshouldnotneedtomaintainseparatestoredproceduresforeachsystem.
·Writingandmaintainingstoredproceduresismostoftenaspecializedskillsetthatnotalldeveloperspossess.Thissituationmayintroducebottlenecksintheprojectdevelopmentschedule.

RecommendationsforUsingStoredProcedureswithDataAccessLogicComponents

Considerthefollowingrecommendationsforusingstoredproceduresinconjunctionwithdataaccesslogiccomponents:
·Exposingstoredprocedures.Dataaccesslogiccomponentsshouldbetheonlycomponentsthatareexposedtodatabaseschemainformation,suchasstoredprocedurenames,parameters,tables,andfields.Yourbusinessentityimplementationshouldhavenoknowledgeofordependencyondatabaseschemas.
·Associatingstoredprocedureswithdataaccesslogiccomponents.EachstoredprocedureshouldbecalledbyonlyoneDataAccessLogicComponent,andshouldbeassociatedwiththeDataAccessLogicComponentthatownstheaction.Forexample,imaginethatacustomerplacesanorderwitharetailer.YoucanwriteastoredprocedurenamedOrderInsert,whichcreatestheorderinthedatabase.Inyourapplication,youmustdecidewhethertocallthestoredprocedurefromtheCustomerDataAccessLogicComponentorfromtheOrderDataAccessLogicComponent.TheOrderDataAccessLogicComponentisabetterchoicebecauseithandlesallorder-relatedprocessing(theCustomerDataAccessLogicComponenthandlescustomerinformation,suchasthecustomer'snameandaddress).
·Namingstoredprocedures.WhenyoudefinestoredproceduresforaDataAccessLogicComponenttouse,choosestoredprocedurenamesthatemphasizetheDataAccessLogicComponenttowhichtheypertain.Thisnamingconventionhelpstoeasilyidentifywhichcomponentscallwhichstoredprocedures,andprovidesawaytologicallygroupthestoredproceduresinsideSQLEnterpriseManager.Forexample,youcanproactivelywritestoredproceduresnamedCustomerInsert,CustomerUpdate,CustomerGetByCustomerID,andCustomerDeleteforusebytheCustomerDataAccessLogicComponent,andthenprovidemorespecificstoredprocedures—suchasCustomerGetAllInRegion—tosupportthebusinessfunctionsofyourapplication.
NoteDonotprefaceyourstoredprocedurenameswithsp_,becausedoingsoreducesperformance.Whenyoucallastoredprocedurethatstartswithsp_,SQLServeralwayschecksthemasterdatabasefirst,evenifthestoredprocedureisqualifiedwiththedatabasename.
·Addressingsecurityissues.Ifyouacceptuserinputtoperformqueriesdynamically,donotcreateastringbyconcatenatingvalueswithoutusingparameters.Alsoavoidusingstringconcatenationinstoredproceduresifyouareusingsp_executetoexecutetheresultingstring,orifyoudonottakeadvantageofsp_executesqlparametersupport.

ManagingLockingandConcurrency

Someapplicationstakethe"LastinWins"approachwhenitcomestoupdatingdatainadatabase.Withthe"LastinWins"approach,thedatabaseisupdated,andnoeffortismadetocompareupdatesagainsttheoriginalrecord,potentiallyoverwritinganychangesmadebyotheruserssincetherecordswerelastrefreshed.However,attimesitisimportantfortheapplicationtodetermineifthedatahasbeenchangedsinceitwasinitiallyread,beforeperformingtheupdate.
Dataaccesslogiccomponentsimplementthecodetomanagelockingandconcurrency.Therearetwowaystomanagelockingandconcurrency:
·Pessimisticconcurrency.Auserwhoreadsarowwiththeintentionofupdatingitestablishesalockontherowinthedatasource.Nooneelsecanchangetherowuntiltheuserreleasesthelock.
·Optimisticconcurrency.Auserdoesnotlockarowwhenreadingit.Otherusersarefreetoaccesstherowinthemeantime.Whenauserwantstoupdatearow,theapplicationmustdeterminewhetheranotheruserhaschangedtherowsinceitwasread.Attemptingtoupdatearecordthathasalreadybeenchangedcausesaconcurrencyviolation.

UsingPessimisticConcurrency

Pessimisticconcurrencyisprimarilyusedinenvironmentswherethereisheavycontentionfordata,andwherethecostofprotectingdatathroughlocksislessthanthecostofrollingbacktransactionsifconcurrencyconflictsoccur.Pessimisticconcurrencyisbestimplementedwhenlocktimeswillbeshort,asinprogrammaticprocessingofrecords.
Pessimisticconcurrencyrequiresapersistentconnectiontothedatabaseandisnotascalableoptionwhenusersareinteractingwithdata,becauserecordsmightbelockedforrelativelylargeperiodsoftime.

UsingOptimisticConcurrency

Optimisticconcurrencyisappropriateinenvironmentswherethereislowcontentionfordata,orwhereread-onlyaccesstodataisrequired.Optimisticconcurrencyimprovesdatabaseperformancebyreducingtheamountoflockingrequired,therebyreducingtheloadonthedatabaseserver.
Optimisticconcurrencyisusedextensivelyin.NETtoaddresstheneedsofmobileanddisconnectedapplications,wherelockingdatarowsforprolongedperiodsoftimewouldbeinfeasible.Also,maintainingrecordlocksrequiresapersistentconnectiontothedatabaseserver,whichisnotpossibleindisconnectedapplications.

TestingforOptimisticConcurrencyViolations

Thereareseveralwaystotestforoptimisticconcurrencyviolations:
·Usedistributedtimestamps.Distributedtimestampsareappropriatewhenreconciliationisnotrequired.Addatimestamporversioncolumntoeachtableinthedatabase.Thetimestampcolumnisreturnedwithanyqueryofthecontentsofthetable.Whenanupdateisattempted,thetimestampvalueinthedatabaseiscomparedtotheoriginaltimestampvaluecontainedinthemodifiedrow.Ifthevaluesmatch,theupdateisperformedandthetimestampcolumnisupdatedwiththecurrenttimetoreflecttheupdate.Ifthevaluesdonotmatch,anoptimisticconcurrencyviolationhasoccurred.
·Maintainacopyoforiginaldatavalues.Whenyouquerydatafromthedatabase,keepacopyofanyoriginaldatavalues.Whenyouupdatethedatabase,verifythatthecurrentvaluesinthedatabasematchtheoriginalvalues.
·DataSetsholdoriginalvaluesthatthedataadaptercanusetoperformoptimisticconcurrencycheckswhenyouupdatethedatabase.
·Usecentralizedtimestamps.Defineacentralizedtimestamptableinyourdatabase,tologallupdatestoanyrowinanytable.Forexample,thetimestamptablecanindicatethefollowing:"RowwithID1234ontableXYZwasupdatedbyJohnonMarch26,20022:56P.M."
Centralizedtimestampsareappropriateincheckoutscenariosandinsomedisconnectedclientscenarioswhereclearownersandmanagementoflocksandoverridesmaybeneeded.Inaddition,centralizedtimestampsprovidethebenefitofauditingwhenneeded.

ManuallyImplementingOptimisticConcurrency

ConsiderthefollowingSQLquery:SELECTColumn1,Column2,Column3FROMTable1
TotestforanoptimisticconcurrencyviolationwhenupdatingarowinTable1,issuethefollowingUPDATEstatement:UPDATETable1SetColumn1=@NewValueColumn1,
SetColumn2=@NewValueColumn2,
SetColumn3=@NewValueColumn3
WHEREColumn1=@OldValueColumn1AND
Column2=@OldValueColumn2AND
Column3=@OldValueColumn3

Iftheoriginalvaluesmatchthevaluesinthedatabase,theupdateisperformed.Ifavaluehasbeenmodified,theupdatewillnotmodifytherowbecausetheWHEREclausewillnotfindamatch.YoucanuseavariationofthistechniqueandapplyaWHEREclauseonlytospecificcolumns,resultingindatabeingoverwrittenunlessparticularfieldshavebeenupdatedsincetheywerelastqueried.
NoteAlwaysreturnavaluethatuniquelyidentifiesarowinyourquery,suchasaprimarykey,touseinyourWHEREclauseoftheUPDATEstatement.ThisensuresthattheUPDATEstatementupdatesthecorrectroworrows.
Ifacolumnatyourdatasourceallowsnulls,youmayneedtoextendyourWHEREclausetocheckforamatchingnullreferenceinyourlocaltableandatthedatasource.Forexample,thefollowingUPDATEstatementverifiesthatanullreferenceinthelocalrowstillmatchesanullreferenceatthedatasource,orthatthevalueinthelocalrowstillmatchesthevalueatthedatasource:UPDATETable1SetColumn1=@NewColumn1Value
WHERE(@OldColumn1ValueISNULLANDColumn1ISNULL)ORColumn1=
@OldColumn1Value

UsingDataAdaptersandDataSetstoImplementOptimisticConcurrency

TheDataAdapter.RowUpdatedeventcanbeusedinconjunctionwiththetechniquesdescribedearliertoprovidenotificationtoyourapplicationofoptimisticconcurrencyviolations.TheRowUpdatedeventoccursaftereachattempttoupdateamodifiedrowfromaDataSet.YoucanusetheRowUpdatedeventtoaddspecialhandlingcode,includingprocessingwhenanexceptionoccurs,addingcustomerrorinformationandaddingretrylogic.
TheRowUpdatedeventhandlerreceivesaRowUpdatedEventArgsobject,whichhasaRecordsAffectedpropertythatindicateshowmanyrowswereaffectedbyanupdatecommandforamodifiedrowinatable.Ifyousettheupdatecommandtotestforoptimisticconcurrency,theRecordsAffectedpropertywillbe0whenanoptimisticconcurrencyviolationoccurs.SettheRowUpdatedEventArgs.Statuspropertytoindicatehowtoproceed;forexample,setthepropertytoUpdateStatus.SkipCurrentRowtoskipupdatingthecurrentrow,buttocontinueupdatingtheotherrowsintheupdatecommand.FormoreinformationabouttheRowUpdatedevent,seeWorkingwithDataAdapterEvents.
AnalternativewaytotestforconcurrencyerrorswithadataadapteristosettheDataAdapter.ContinueUpdateOnErrorpropertytotruebeforeyoucalltheUpdatemethod.Whentheupdateiscompleted,calltheGetErrorsmethodontheDataTableobjecttodeterminewhichrowshaveerrors.Then,usetheRowErrorpropertyontheserowstofindspecificerrordetails.Formoreinformationabouthowtoprocessrowerrors,seeAddingandReadingRowErrorInformation.
ThefollowingcodesampleshowshowtheCustomerDataAccessLogicComponentcancheckforconcurrencyviolations.ThisexampleassumesthattheclienthasretrievedaDataSet,madechangestothedata,andthenpassedtheDataSettotheUpdateCustomermethodontheDataAccessLogicComponent.TheUpdateCustomermethodwillinvokethefollowingstoredproceduretoupdatetheappropriatecustomerrecord;thestoredprocedureupdatestherecordonlyifthecustomerIDandcompanynamehavenotalreadybeenmodified:CREATEPROCEDURECustomerUpdate
{
@CompanyNamevarchar(30),
@oldCustomerIDvarchar(10),
@oldCompanyNamevarchar(30)
}
AS
UPDATECustomersSetCompanyName=@CompanyName
WHERECustomerID=@oldCustomerIDANDCompanyName=@oldCompanyName
GO

InsidetheUpdateCustomermethod,thefollowingcodesamplesetstheUpdateCommandpropertyofadataadaptertotestforoptimisticconcurrency,andthenusestheRowUpdatedeventtotestforoptimisticconcurrencyviolations.Ifanoptimisticconcurrencyviolationisencountered,theapplicationindicatestheviolationbysettingtheRowErroroftherowforwhichtheupdatewasissued.NotethattheparametervaluespassedtotheWHEREclauseoftheUPDATEcommandaremappedtotheOriginalvaluesoftherespectivecolumnsintheDataSet.//UpdateCustomermethodintheCustomerDALCclass
publicvoidUpdateCustomer(DataSetdsCustomer)
{
//ConnecttotheNorthwinddatabase
SqlConnectioncnNorthwind=newSqlConnection(
"Datasource=localhost;Integratedsecurity=SSPI;Initial
Catalog=northwind");
//CreateaDataAdaptertoaccesstheCustomerstableinNorthwind
SqlDataAdapterda=newSqlDataAdapter();
//SettheDataAdapter'sUPDATEcommand,tocallthe"UpdateCustomer"
storedprocedure
da.UpdateCommand=newSqlCommand("CustomerUpdate",cnNorthwind);
da.UpdateCommand.CommandType=CommandType.StoredProcedure;
//AddtwoparameterstotheDataAdapter'sUPDATEcommand,tospecify
information
//fortheWHEREclause(tofacilitatecheckingforoptimisticconcurrency
violation)
da.UpdateCommand.Parameters.Add("@CompanyName",SqlDbType.NVarChar,30,
"CompanyName");
//SpecifytheoriginalvalueofCustomerIDasthefirstWHEREclause
parameter
SqlParametermyParm=da.UpdateCommand.Parameters.Add(
"@oldCustomerID",SqlDbType.NChar,5,
"CustomerID");
myParm.SourceVersion=DataRowVersion.Original;
//SpecifytheoriginalvalueofCustomerNameasthesecondWHEREclause
parameter
myParm=da.UpdateCommand.Parameters.Add(
"@oldCompanyName",SqlDbType.NVarChar,30,
"CompanyName");
myParm.SourceVersion=DataRowVersion.Original;
//AddahandlerforRowUpdateevents
da.RowUpdated+=newSqlRowUpdatedEventHandler(OnRowUpdated);
//Updatethedatabase
da.Update(ds,"Customers");
foreach(DataRowmyRowinds.Tables["Customers"].Rows)
{
if(myRow.HasErrors)
Console.WriteLine(myRow[0]+""+myRow.RowError);
}
}
//MethodtohandleRowUpdateevents.Ifyouregistertheeventbutdonot
handleit,
//aSQLexceptionisthrown.
protectedstaticvoidOnRowUpdated(objectsender,SqlRowUpdatedEventArgs
args)
{
if(args.RecordsAffected==0)
{
args.Row.RowError="OptimisticConcurrencyViolationEncountered";
args.Status=UpdateStatus.SkipCurrentRow;
}
}

WhenexecutingmultipleSQLstatementswithinoneSQLServerstoredprocedure,youmay,forperformancereasons,choosetousetheSETNOCOUNTONoption.ThisoptionpreventsSQLServerfromreturningamessagetotheclientaftercompletionofeachstatement,thusreducingnetworktraffic.However,youwillnotbeabletochecktheRecordsAffectedpropertyasdemonstratedinthepreviouscodesample.TheRecordsAffectedpropertywillalwaysbe–1.Analternativeistoreturnthe@@ROWCOUNTfunction(orspecifyitasanoutputparameter)inyourstoredprocedure;@@ROWCOUNTcontainstherecordcountforthelaststatementcompletedinyourstoredprocedureandisupdatedevenwhenSETNOCOUNTONisused.Therefore,ifthelastSQLstatementexecutedinyourstoredprocedureistheactualUPDATEstatementandyouspecifythe@@ROWCOUNTasareturnvalue,youcanmodifyapplicationcodeasfollows://AddanotherparametertoDataAdapter'sUPDATEcommand,toacceptthe
returnvalue.
//Youcannameitanythingyouwant.
myParm=da.UpdateCommand.Parameters.Add("@RowCount",SqlDbType.Int);
myParm.Direction=ParameterDirection.ReturnValue;
//ModifytheOnRowUpdatedmethod,tocheckthevalueofthisparameter
//insteadoftheRecordsAffectedproperty.
protectedstaticvoidOnRowUpdated(objectsender,SqlRowUpdatedEventArgs
args)
{
if(args.Command.Parameters["@RowCount"].Value==0)
{
args.Row.RowError="OptimisticConcurrencyViolationEncountered";
args.Status=UpdateStatus.SkipCurrentRow;
}
}

COMInteroperability

IfyouwantyourDataAccessLogicComponentclasstobecallablefromCOMclients,therecommendedapproachistodefineyourdataaccesslogiccomponentsbyusingtheprecedingguidelinesandprovideawrappercomponent.However,ifyouwantCOMclientstobeabletoaccessyourdataaccesslogiccomponents,considerthefollowingrecommendations:
·Definetheclassanditsmembersaspublic.
·Avoidusingstaticmembers.
·Defineevent-sourceinterfacesinmanagedcode.
·Provideaconstructorthatdoesnotuseparameters.
·Donotuseoverloadedmethods.Usemethodswithdifferentnamesinstead.
·Useinterfacestoexposecommonoperations.
·UseattributestoprovideextraCOMinformationforyourclassandmembers.
·IncludeHRESULTvaluesinanyexceptionsthrownfrom.NETcode.
·Useautomation-compatibledatatypesinmethodsignatures.
FormoreinformationaboutCOMinteroperability,seetheMicrosoft.NET/COMMigrationandInteroperabilityguide.

ImplementingBusinessEntities

Businessentitiesexhibitthefollowingcharacteristics:
·Businessentitiesprovidestatefulprogrammaticaccesstobusinessdataand(insomedesigns)relatedfunctionality.
·Businessentitiescanbebuiltfromdatathathascomplexschemas.Thedatatypicallyoriginatesfrommultiplerelatedtablesinthedatabase.
·BusinessentitydatacanbepassedaspartoftheI/Oparametersofbusinessprocesses.
·Businessentitiescanbeserializable,topersistthecurrentstateoftheentities.Forexample,applicationsmayneedtostoreentitydataonalocaldisk,inadesktopdatabaseiftheapplicationisworkingoffline,orinaMessageQueuingmessage.
·Businessentitiesdonotaccessthedatabasedirectly.AlldatabaseaccessisprovidedbytheassociatedDataAccessLogicComponent.
·Businessentitiesdonotinitiateanykindoftransaction.Transactionsareinitiatedbytheapplicationorbusinessprocessthatisusingthebusinessentities.
Asmentionedearlierinthisdocument,therearevariouswaystorepresentbusinessentitiesinyourapplication,rangingfromadata-centricmodeltoamoreobject-orientedrepresentation:
·XML
·GenericDataSet
·TypedDataSet
·Custombusinessentitycomponents
·CustombusinessentitycomponentswithCRUDbehaviors
Thesectionsthatfollowdescribehowtorepresentbusinessentitydataineachoftheseformats.Tohelpyoudecidethemostappropriaterepresentationforbusinessentitiesinyourparticularcircumstances,thesectionsdescribehowtoperformthefollowingtasksforeachbusinessentityformat:
·Organizecollectionsofbusinessentities
·Databindbusinessentitiestouser-interfacecontrols
·Serializebusinessentitydata
·Passbusinessentitydatabetweentiers
Thesectionsalsoconsiderthesuitabilityofeachbusinessentityrepresentationintermsofnonfunctionalrequirements,includingperformance,efficiency,scalability,andextensibility.

RepresentingBusinessEntitiesasXML

ThefollowingexampleshowshowtorepresentasimplebusinessentityasXML.Thebusinessentityconsistsofasingleproduct.<?xmlversion="1.0"?>
<Productxmlns="urn:aUniqueNamespace">
<ProductID>1</ProductID>
<ProductName>Chai</ProductName>
<QuantityPerUnit>10boxesx20bags</QuantityPerUnit>
<UnitPrice>18.00</UnitPrice>
<UnitsInStock>39</UnitsInStock>
<UnitsOnOrder>0</UnitsOnOrder>
<ReorderLevel>10</ReorderLevel>
</Product>

Formoreinformation,seeHowtoUseXMLtoRepresentCollectionsandHierarchiesofDataintheappendix.
WhenyouuseXMLtorepresentbusinessentitydata,considerthefollowingguidelines:
·DecidewhethertheXMLdocumentshouldcontainasinglebusinessentityoracollectionofbusinessentities.TheprecedingexamplerepresentsasingleProductbusinessentity.
·UseanamespacetouniquelyidentifytheXMLdocument,toavoidnameclasheswithcontentinotherXMLdocuments.Theprecedingexampleusesadefaultnamespacecalledurn:aUniqueNamespace.
·Chooseappropriatenamesforelementsandattributes.TheprecedingexampleusesthecolumnnamesfromtheProducttable,butthisisnotarequirement.Choosenamesthatmakesenseforyourapplication.
·UseoneofthefollowingapproachestoretrieveyourbusinessentitiesinXMLformat:
·IfyouareusingSQLServer2000,youcanusetheFORXMLclauseinyourqueriesorstoredprocedures.Inperformancetests,usingFORXMLisonlyslightlyfasterthanreturningaDataSet.
·RetrieveaDataSetandtransformitorwriteitoutasanXMLstream.Withthisapproach,youincurtheoverheadofcreatingtheDataSetandadditionaloverheadifperformingatransformation.
·BuildanXMLdocumentfromoutputparametersorbyusingadatareader.Datareadersarethefastestwaytoretrievemultiplerowsfromthedatabase,buttheprocessassociatedwithbuildingXMLmaydecreasetheperformancebenefit.
Formoreinformationandperformanceconsiderations,seePerformanceComparison:DataAccessTechniques.
TheadvantagesofrepresentingbusinessentitiesasXMLareasfollows:
·Standardssupport.XMLisaWorldWideWebConsortium(W3C)standarddatarepresentationformat.Formoreinformationaboutthisstandard,seehttp://www.w3.org/xml.
·Flexibility.XMLcanrepresenthierarchiesandcollectionsofinformation.Formoreinformation,seeHowtoUseXMLtoRepresentCollectionsandHierarchiesofDataintheappendix.
·Interoperability.XMLisanidealchoiceforexchanginginformationwithexternalpartiesandtradingpartners,regardlessofplatform.IftheXMLdatawillbeconsumedbyASP.NETorWindowsFormsapplications,youcanloadtheXMLdataintoaDataSettotakeadvantageofthedatabindingsupportprovidedbyDataSets.
ThedisadvantagesofrepresentingbusinessentitiesasXMLareasfollows:
·Preservingtypefidelity.TypefidelityisnotpreservedinXML.However,youcanuseXSDschemasforsimpledatatyping.
·ValidatingXML.TovalidateXML,youcanparsethecodemanuallyoruseanXSDschema.Bothapproachesarerelativelyslow.ForanexampleofhowtovalidateXMLbyusinganXSDschema,seeHowtoValidateXMLbyUsinganXSDSchema.
·DisplayingXML.YoucannotautomaticallydisplayXMLdataintheuserinterface.YoucanwriteanXSLTstylesheettotransformthedataintoaDataSet;however,stylesheetsarenoteasytowrite.Alternatively,thestylesheetcantransformtheXMLintoadisplayableformatsuchasHTML.Formoreinformation,seeHowtoApplyaStyleSheetProgrammaticallyina.NETApplicationintheappendix.
·ParsingXML.ToparseXML,youcanusetheDocumentObjectModel(DOM)ortheXmlReaderclassprovidedintheMicrosoft.NETFrameworkclasslibrary.XmlReaderprovidesfast-forwardonly,read-onlyaccesstoXMLdata,butDOMismoreflexiblebecauseitprovidesrandomread/writeaccess.However,parsinganXMLdocumentbyusingDOMisslower;youmustcreateaninstanceofXmlDocument(oranotherXMLparserclass)andloadtheentireXMLdocumentintomemory.
·SortingXML.YoucannotautomaticallysortXMLdata.Instead,useoneofthefollowingtechniques:
·Deliverthedatainpresortedorder.Thisoptiondoesnotsupportdynamicresortingofdatainthecallingapplication.
·ApplyanXSLTstylesheettosortthedatadynamically.Ifnecessary,youcanalterthesortcriteriaintheXSLTstylesheetatruntime,byusingDOM.
·TransformtheXMLdataintoaDataSet,anduseaDataViewobjecttosortandsearchthedataelements.
·Usingprivatefields.Youdonothavetheoptionofhidinginformation.

RepresentingBusinessEntitiesAsaGenericDataSet

AgenericDataSetisaninstanceoftheDataSetclass,whichisdefinedintheSystem.DatanamespaceinADO.NET.ADataSetobjectcontainsoneormoreDataTableobjectstorepresentinformationthattheDataAccessLogicComponentretrievesfromthedatabase.
Figure7showsagenericDataSetobjectfortheProductbusinessentity.TheDataSetobjecthasasingleDataTabletoholdinformationforproducts.TheDataTablehasaUniqueConstraintobjecttodenotetheProductIDcolumnasaprimarykey.TheDataTableandUniqueConstraintobjectsarecreatedwhentheDataSetiscreatedintheDataAccessLogicComponent.

Figure7.GenericDataSetfortheProductbusinessentity
Figure8showsagenericDataSetobjectfortheOrderbusinessentity.ThisDataSetobjecthastwoDataTableobjectstoholdinformationfortheordersandorderdetails,respectively.EachDataTablehasacorrespondingUniqueConstraintobjecttoidentifytheprimarykeyinthattable.Additionally,theDataSethasaRelationobjecttoassociateorderdetailswithorders.

Figure8.GenericDataSetfortheOrderbusinessentity
ThefollowingcodeshowshowtoretrieveagenericDataSetfromaDataAccessLogicComponent,bindtheDataSettoaDataGridcontrol,andthenpasstheDataSettotheDataAccessLogicComponenttosavedatachanges://CreateaProductDALCobject
ProductDALCdalcProduct=newProductDALC();
//CallamethodonProductDALCtogetaDataSetcontaininginformationfor
allproducts
DataSetdsProducts=dalcProduct.GetProducts();
//UseDataSetintheclient.Forexample,bindtheDataSettouserinterface
controls
dataGrid1.DataSource=dsProducts.Tables[0].DefaultView;
dataGrid1.DataBind();
//Whenyouareready,passtheupdatedDataSettotheProductDALCtosave
thechanges
//backtothedatabase
dalcProduct.UpdateProducts(dsProducts);

Youcanalsoqueryandmodifythetables,constraints,andrelationsinaDataSetatruntime.Formoreinformation,seeCreatingandUsingDataSets.
TheadvantagesofrepresentingbusinessentitiesasagenericDataSetareasfollows:
·Flexibility.DataSetscancontaincollectionsofdata,andcanrepresentcomplexdatarelationships.
·Serialization.DataSetsnativelysupportserializationwhenpassingacrosstiers.
·Databinding.DataSetscanbeboundtoanyuser-interfacecontrolsinASP.NETandWindowsFormsapplications.
·Sortingandfiltering.DataSetscanbesortedandfilteredbyusingDataViewobjects.AnapplicationcancreateseveralDataViewobjectsforthesameDataSet,toviewthedataindifferentways.
·&nb
24000
sp;InterchangeabilitywithXML.DataSetscanbereadorwritteninXMLformat.Thisisausefultechniqueinremoteanddisconnectedapplications,whichcanreceiveaDataSetinXMLformatandrecreatetheDataSetobjectlocally.ApplicationscanalsopersistDataSetstoXMLformatwhiletheapplicationsaredisconnectedfromthedatabase.
·Availabilityofmetadata.FullmetadatacanbeprovidedforaDataSet,intheformofanXSDschema.YoucanalsoprogrammaticallyobtainmetadatafortheDataSetbyusingmethodsintheDataSet,DataTable,DataColumn,Constraint,andRelationclasses.
·Optimisticconcurrency.Whenyouareupdatingdata,youcanuseDataSets,inconjunctionwithdataadapters,toperformoptimisticconcurrencycheckseasily.
·Extensibility.Ifthedatabaseschemaismodified,themethodsintheDataAccessLogicComponentcancreateDataSetsthatcontainmodifiedDataTableandDataRelationobjectsasappropriate.TheDataAccessLogicComponentmethodsignaturesdonotchange.ThecallingapplicationcanbemodifiedtousethesenewelementsintheDataSet.
ThedisadvantagesofrepresentingbusinessentitiesasagenericDataSetareasfollows:
·ClientcodemustaccessdatathroughcollectionsintheDataSet.ToaccessatableinaDataSet,clientcodemustindexintotheDataTablecollectionsbyusinganintegerindexerorastringindexer.Toaccessaparticularcolumn,youmustindexintotheDataColumncollectionbyusingacolumnnumberoracolumnname.ThefollowingexampleshowshowtoaccesstheProductNamecolumnforthefirstrowintheProductstable:·Ã‚Â…
·//Gettheproductnamefortheproductinthefirstrowofa
·DataSetcalled
·//dsProducts.Notethecollectionsarezero-based.
·Stringstr=(String)dsProducts.Tables["Products"].Rows[0]["ProductName"];
·Ã‚Â…

NoteNotethatthereisnocompile-timecheckingoftheseindexervalues.Ifyouspecifyaninvalidtablename,columnname,orcolumntype,theerroristrappedatruntime.ThereisnoIntelliSensesupportwhenyouusegenericDataSets.
·Highinstantiationandmarshallingcosts.DataSetsresultinthecreationofseveralsubobjects(DataTable,DataRow,andDataColumn),whichmeansthatDataSetscantakelongertoinstantiateandmarshalthanXMLstringsorcustomentitycomponents.TherelativeperformanceofDataSetsimprovesastheamountofdataincreases,becausetheoverheadofcreatingtheinternalstructureoftheDataSetislesssignificantthanthetimeittakestopopulatetheDataSetwithdata.
·Privatefields.Youdonothavetheoptionofhidinginformation.

RepresentingBusinessEntitiesAsaTypedDataSet

AtypedDataSetisaclassthatcontainsstronglytypedmethods,properties,andtypedefinitionstoexposethedataandmetadatainaDataSet.ForanexampleofhowtocreateatypedDataSet,seeHowtoCreateaTypedDataSetintheappendix.
ThefollowinglistsdescribetheadvantagesanddisadvantagesoftypedDataSets,comparedwithgenericDataSets.NotethattypedDataSetsexhibitapproximatelythesameinstantiationandmarshallingperformanceasgenericDataSets.
TheadvantagesofrepresentingbusinessentitiesasatypedDataSetareasfollows:
·Codereadability.ToaccesstablesandcolumnsinatypedDataSet,youcanusetypedmethodsandproperties,asshowninthefollowingcode:·Ã‚Â…
·//Gettheproductnamefortheproductinthefirstrowofatyped
·DataSetcalled
·//dsProducts.Notethecollectionsarezero-based.
·Stringstr=dsProducts.Products[0].ProductName;
·Ã‚Â…

Inthisexample,dsProductsisaninstanceofatypedDataSet.TheDataSethasasingleDataTable,whichisexposedbyapropertynamedProducts.ThecolumnsinthisDataTableareexposedbypropertiessuchasProductName,whichreturnstheappropriatedatatypeforthecolumn(ratherthanjustreturningObject).
TheprovisionoftypedmethodsandpropertiesmakestypedDataSetseasiertousethangenericDataSets.WhenyouusetypedDataSets,IntelliSenseisavailable.
·Compiletypechecking.Invalidtablenamesandcolumnnamesaredetectedatcompiletimeratherthanatruntime.
ThedisadvantagesofrepresentingbusinessentitiesasatypedDataSetareasfollows:
·Deployment.TheassemblycontainingthetypedDataSetclassmustbedeployedtoalltiersthatusethebusinessentity.
·SupportofEnterpriseServices(COM+)callers.IfatypedDataSetwillbeusedbyCOM+clients,theassemblycontainingthetypedDataSetclassmustbegivenastrongnameandmustberegisteredonclientcomputers.Typically,theassemblyisinstalledintheglobalassemblycache.Thesestepswillalsoberequiredforcustomentityclasses,asdescribedlaterinthisdocument.
·Extensibilityissues.Ifthedatabaseschemaismodified,thetypedDataSetclassmightneedtoberegeneratedtosupportthenewschema.TheregenerationprocesswillnotpreserveanycustomcodethatwasimplementedinthetypedDataSetclass.TheassemblycontainingthetypedDataSetclassmustberedeployedtoallclientapplications.
·Instantiation.Youcannotinstantiatethetypebyusingthenewoperator.
·Inheritance.YourtypeddatasetmustinheritfromDataSet,whichprecludestheuseofanyotherbaseclasses.

DefiningCustomBusinessEntityComponents

Customclassesthatrepresentbusinessentitiestypicallycontainthefollowingmembers:
·Privatefieldstocachethebusinessentity'sdatalocally.ThesefieldsholdasnapshotofthedatainthedatabaseatthetimethedatawasretrievedfromthedatabasebytheDataAccessLogicComponent.
·Publicpropertiestoaccessthestateoftheentity,andtoaccesssubcollectionsandhierarchiesofdatainsidetheentity.Thepropertiescanhavethesamenamesasthedatabasecolumnnames,butthisisnotanabsoluterequirement.Choosepropertynamesaccordingtotheneedsofyourapplication,ratherthanthenamesinthedatabase.
·Methodsandpropertiestoperformlocalizedprocessingbyusingthedataintheentitycomponent.
·Eventstosignalchangestotheinternalstateoftheentitycomponent.
Figure9showshowcustomentityclassesareused.NotethattheentityclasshasnoknowledgeoftheDataAccessLogicComponentortheunderlyingdatabase;alldatabaseaccessisperformedbytheDataAccessLogicComponenttocentralizedataaccesspoliciesandbusinesslogic.Also,thewayinwhichyoupassbusinessentitydatathroughthetiersisnotdirectlytiedtotheformatofyourbusinessentityrepresentation;forexample,youcanrepresentbusinessentitieslocallyasobjects,yetchooseadifferentapproach(suchasscalarvaluesorXML)topassbusinessentitydatatoadifferenttier.

Figure9.Theroleofcustombusinessentitycomponents(clickthumbnailforlargerimage)

RecommendationsforDefiningCustomBusinessEntityComponents

Tohelpyouimplementyourcustomentitycomponents,considerthefollowingrecommendations:
·Choosingbetweenstructsandclasses.Forsimplebusinessentitiesthatdonotcontainhierarchicaldataorcollections,considerdefiningastructtorepresentthebusinessentity.Forcomplexbusinessentities,orforbusinessentitiesthatrequireinheritance,definetheentityasaclassinstead.Foracomparisonofstructandclasstypes,seeStructuresandClasses.
·Representingthebusinessentity'sstate.Forsimplevaluessuchasnumbersandstrings,definefieldsbyusingtheequivalent.NETdatatype.Foracodeexamplethatshowshowtodefineacustomentity,seeHowtoDefineaBusinessEntityComponentsintheappendix.
·RepresentingsubcollectionsandhierarchiesinacustomBusinessEntityComponent.Therearetwowaystorepresentsubcollectionsandhierarchiesofdatainacustomentity:
·A.NETcollectionsuchasArrayList.The.NETcollectionclassesofferaconvenientprogrammingmodelforresizablecollections,andalsoprovidebuilt-insupportfordatabindingtouser-interfacecontrols.
·ADataSet.DataSetsarewellsuitedforstoringcollectionsandhierarchiesofdatafromarelationaldatabaseorfromanXMLdocument.Additionally,DataSetsarepreferredifyouneedtobeabletofilter,sort,ordatabindyoursubcollections.
Foracodeexamplethatshowshowtorepresentcollectionsandhierarchiesofdatainacustomentity,seeHowtoRepresentCollectionsandHierarchiesofDatainaBusinessEntityComponentintheappendix.
·Supportingdatabindingforuser-interfaceclients.Ifthecustomentitywillbeconsumedbyuserinterfacesandyouwanttotakeadvantageofautomaticdatabinding,youmayneedtoimplementdatabindinginyourcustomentity.Considerthefollowingscenarios:
·DatabindinginWindowsForms.Youcandatabindanentityinstancetocontrolswithoutimplementingdatabindinginterfacesinyourcustomentity.Youcanalsodatabindanarrayora.NETcollectionofentities.
·DatabindinginWebForms.YoucannotdatabindanentityinstancetocontrolsinaWebFormwithoutimplementingtheIBindingListinterface.However,ifyouwanttodatabindonlysets,youcanuseanarrayora.NETcollectionwithoutneedingtoimplementtheIBindingListinterfaceinyourcustomentity.
Foracodeexamplethatshowshowtobindcustomentitiestouser-interfacecontrols,seeHowtoBindBusinessEntityComponentstoUser-InterfaceControlsintheappendix.
·Exposingeventsforinternaldatachanges.Exposingeventsisusefulforrich-clientuser-interfacedesignbecauseitenablesdatatoberefreshedwhereveritisbeingdisplayed.Theeventsshouldbeforinternalstateonly,notfordatachangesonaserver.Foracodeexamplethatshowshowtoexposeeventsinacustomentityclass,seeHowtoExposeEventsinaBusinessEntityComponentintheappendix.
·Makingyourbusinessentitiesserializable.Makingbusinessentitiesserializableenablesthebusinessentity'sstatetobepersistedininterimstateswithoutdatabaseinteractions.Theresultcanbetoeaseofflineapplicationdevelopmentanddesignofcomplexuserinterfaceprocessesthatdonotaffectbusinessdatauntiltheyarecomplete.Therearetwotypesofserialization:
·XMLserializationbyusingtheXmlSerializerclass.UseXMLserializationwhenyouneedtoserializeonlypublicfieldsandpublicread/writepropertiestoXML.NotethatifyoureturnbusinessentitydatafromaWebservice,theobjectisautomaticallyserializedtoXMLthroughXMLserialization.
YoucanperformXMLserializationonbusinessentitieswithoutimplementinganyadditionalcodeinsidetheentity.However,onlythepublicfieldsandpublicread/writepropertiesintheobjectareserializedtoXML.Privatefields,indexers,privateproperties,read-onlypropertiesandobjectgraphsarenotserialized.YoucancontroltheresultingXMLbyusingattributesinyourcustomentity.FormoreinformationabouthowtoserializecustomentitycomponentstoXMLformat,seeHowtoSerializeBusinessEntityComponentstoXMLFormatintheappendix.
·FormattedserializationbyusingtheBinaryFormatterorSoapFormatterclass.Useformattedserializationwhenyouneedtoserializeallthepublicandprivatefieldsandobjectgraphsofanobject,orifyouwillpassanentitycomponenttoorfromaremotingserver.
Theformatterclassesserializeallofanobject'sfieldsandproperties,bothpublicandprivate.BinaryFormatterserializestheobjecttobinaryformat,andSoapFormatterserializesanobjecttoSOAPformat.SerializationbyusingBinaryFormatterisfasterthanserializationbyusingSoapFormatter.Touseeitheroftheseformatterclasses,youmustmarkyourentityclasswiththe[Serializable]attribute.Ifyouneedexplicitcontrolovertheserializationformat,yourclassmustalsoimplementtheISerializableinterface.Formoreinformationabouthowtouseformattedserialization,seeHowtoSerializeBusinessEntityComponentstoBinaryFormatandHowtoSerializeBusinessEntityComponentstoSOAPFormatintheappendix.
·NoteDefaultconstructorsarenotcalledwhenanobjectisdeserialized.Thisconstraintisplacedondeserializationforperformancereasons.
Theadvantagesofdefiningacustomentityareasfollows:
·Codereadability.Toaccessdatainacustomentityclass,youcanusetypedmethodsandproperties,asshowninthefollowingcode:·//CreateaProductDALCobject
·ProductDALCdalcProduct=newProductDALC();
·
·//UsetheProductDALCobjecttocreateandpopulateaProductEntity
·object.
·//ThiscodeassumestheProductDALCclasshasamethodnamedGetProduct,
·//whichtakesaProductIDasaparameter(21inthisexample)and
·returnsa
·//ProductEntityobjectcontainingallthedataforthisproduct.
·ProductEntityaProduct=dalcProduct.GetProduct(21);
·
·//Changetheproductnameforthisproduct
·aProduct.ProductName="RoastedCoffeeBeans";

Intheprecedingexample,aproductisaninstanceofacustomentityclassnamedProductEntity.TheProductDALCclasshasamethodnamedGetProduct,whichcreatesaProductEntityobject,populatestheobjectwithdataforaspecificproductandreturnstheProductEntityobject.ThecallingapplicationcanusepropertiessuchasProductNametoaccessthedataontheProductEntityobjectandcancallmethodstomanipulatetheobject.
·Encapsulation.Customentitiescancontainmethodstoencapsulatesimplebusinessrules.Thesemethodsoperateonthebusinessentitydatacachedintheentitycomponent,ratherthanaccessingthelivedatainthedatabase.Considerthefollowingexample:·//CallamethoddefinedintheProductEntityclass.
·aProduct.IncreaseUnitPriceBy(1.50);

Intheprecedingexample,thecallingapplicationcallsamethodnamedIncreaseUnitPriceByontheProductEntityobject.ThischangeisnotmadepermanentuntiltheProductEntityobjectissavedbacktothedatabasewhenthecallingapplicationinvokesanappropriatemethodontheProductDALCobject.
·Modelingofcomplexsystems.Ifyouaremodelingacomplexdomainproblemthathasmanyinteractionsbetweendifferentbusinessentities,itmaybebeneficialtodefinecustomentityclassestoabsorbthecomplexitybehindwell-definedclassinterfaces.
·Localizedvalidation.Customentityclassescanperformsimplevalidationtestsintheirpropertyaccessorstodetectinvalidbusinessentitydata.Formoreinformation,seeHowtoValidateDatainPropertyAccessorsinBusinessEntityComponents.
·Privatefields.Youcanhideinformationthatyoudonotwanttoexposetothecaller.
Thedisadvantagesofdefiningacustomentityareasfollows:
·Collectionsofbusinessentities.Acustomentityrepresentsasinglebusinessentity,notacollectionofbusinessentities.Thecallingapplicationmustcreateanarrayora.NETcollectiontoholdmultiplebusinessentities.
·Serialization.Youmustimplementyourownserializationmechanisminacustomentity.Youcanuseattributestocontrolhowentitycomponentsareserialized,oryoucanimplementtheISerializableinterfacetocontrolyourownserialization.
·Representationofcomplexrelationshipsandhierarchiesinabusinessentity.YoumustimplementyourownmechanismforrepresentingrelationshipsandhierarchiesofdatainaBusinessEntityComponent.Asdescribedpreviously,DataSetsareoftentheeasiestwaytoachievethiseffect.
·Searchingandsortingofdata.Youmustdefineyourownmechanismtosupportsearchingandsortingofentities.Forexample,youcanimplementtheIComparableinterfacetoallowentitycomponentstobeheldinaSortedListorHashtablecollection.
·Deployment.Youmustdeploy,onallphysicaltiers,theassemblycontainingthecustomentity.
·SupportforEnterpriseServices(COM+)clients.IfacustomentitywillbeusedbyCOM+clients,theassemblycontainingtheentitymustbegivenastrongnameandmustberegisteredonclientcomputers.Typically,theassemblyisinstalledintheglobalassemblycache.
·Extensibilityissues.Ifthedatabaseschemaismodified,youmightneedtomodifythecustomentityclassandredeploytheassembly.

DefiningCustomBusinessEntityComponentswithCRUDBehaviors

Whenyoudefineacustomentity,youcanprovidemethodstocompletelyencapsulatetheCRUDoperationsontheunderlyingDataAccessLogicComponent.Thisisthemoretraditionalobject-orientedapproach,andmaybeappropriateforcomplexobjectdomains.TheclientapplicationnolongeraccessestheDataAccessLogicComponentclassdirectly.Instead,theclientapplicationcreatesanentitycomponentandcallsCRUDmethodsontheentitycomponent.ThesemethodsforwardtotheunderlyingDataAccessLogicComponent.
Figure10showstheroleofcustomentityclasseswithCRUDbehaviors.

Figure10.TheroleofcustombusinessentitycomponentswithCRUDbehaviors(clickthumbnailforlargerimage)
TheadvantagesofdefiningcustomentityclasseswithCRUDbehaviorsareasfollows:
·Encapsulation.ThecustomentityencapsulatestheoperationsdefinedbytheunderlyingDataAccessLogicComponent.
·Interfacetocaller.Thecallermustdealwithonlyoneinterfacetopersistbusinessentitydata.ThereisnoneedtoaccesstheDataAccessLogicComponentdirectly.
·Privatefields.Youcanhideinformationthatyoudonotwanttoexposetothecaller.
ThedisadvantagesofdefiningcustomentityclasseswithCRUDbehaviorsareasfollows:
·Dealingwithsetsofbusinessentities.Themethodsinthecustomentitypertaintoasinglebusinessentityinstance.Tosupportsetsofbusinessentities,youcandefinestaticmethodsthattakeorreturnanarrayoracollectionofentitycomponents.
·Increaseddevelopmenttime.Thetraditionalobject-orientedapproachtypicallyrequiresmoredesignanddevelopmenteffortthanworkingwithexistingobjects,suchasDataSets,requires.

RecommendationsforRepresentingDataandPassingDataThroughTiers

Thewayinwhichyourepresentdatathroughoutyourapplication,andthewayinwhichyoupassthatdatathroughthetiers,donotnecessarilyneedtobethesame.However,havingaconsistentandlimitedsetofformatsyieldsperformanceandmaintenancebenefitsthatreduceyourneedforadditionaltranslationlayers.
Thedataformatthatyouuseshoulddependonyourspecificapplicationrequirementsandhowyouwanttoworkwiththedata.Thereisnouniversalwaytorepresentyourdata,especiallybecausemanyoftoday'sapplicationsarerequiredtosupportmultiplecallers.However,itisrecommendedthatyoufollowthesegeneralguidelines:
·Ifyourapplicationmainlyworkswithsetsandneedsfunctionalitysuchassorting,searchinganddatabinding,Datasetsarerecommended.However,ifyourapplicationworkswithinstancedata,scalarvalueswillperformbetter.
·Ifyourapplicationmainlyworkswithinstancedata,custombusinessentitycomponentsmaybethebestchoicebecausetheypreventtheoverheadcausedwhenaDataSetrepresentsonerow.
·Inmostcases,designyourapplicationtouseadata-centricformat,suchasXMLdocumentsorDataSets.YoucanusetheflexibilityandnativefunctionalityprovidedbytheDataSetstosupportmultipleclientsmoreeasily,reducetheamountofcustomcode,anduseaprogrammingAPIthatisfamiliartomostdevelopers.Althoughworkingwiththedatainanobject-orientedfashionprovidessomebenefits,customcodingcomplexbusinessentitiesincreasesdevelopmentandmaintenancecostsinproportiontotheamountoffeaturesyouwanttoprovide.

Transactions

Mostoftoday'sapplicationsneedtosupporttransactionsformaintainingtheintegrityofasystem'sdata.Thereareseveralapproachestotransactionmanagement;however,eachapproachfitsintooneoftwobasicprogrammingmodels:
·Manualtransactions.YouwritecodethatusesthetransactionsupportfeaturesofeitherADO.NETorTransact-SQLdirectlyinyourcomponentcodeorstoredprocedures,respectively.
·Automatictransactions.UsingEnterpriseServices(COM+),youadddeclarativeattributestoyour.NETclassestospecifythetransactionalrequirementsofyourobjectsatruntime.Youcanusethismodeltoeasilyconfiguremultiplecomponentstoperformworkwithinthesametransaction.
Thissectionprovidesguidanceandrecommendationstohelpyouimplementtransactionsupportindataaccesslogiccomponentsandbusinessentitycomponents.Forexamplesandamorein-depthdiscussionoftransactionsin.NET,seethe.NETDataAccessArchitectureGuide.

ImplementingTransactions

Inmostcircumstances,therootofthetransactionisthebusinessprocessratherthanaDataAccessLogicComponentoraBusinessEntityComponent.Thereasonisthatbusinessprocessestypicallyrequiretransactionsthatspanmultiplebusinessentities,notjustasinglebusinessentity.
However,situationsmayarisewhereyouneedtoperformtransactionaloperationsonasinglebusinessentitywithouttheassistanceofahigher-levelbusinessprocess.Forexample,toaddanewcustomertothedatabasediscussedearlier,youmustperformthefollowingoperations:
·InsertanewrowintheCustomertable.
·InsertanewroworrowsintheAddresstable.
Bothoftheseoperationsmustsucceed,orthecustomerwillnotbeaddedtothedatabase.IftheCustomerbusinessentitywillneverbeapartofalargerbusinessprocessthatwillinitiatethetransaction,usemanualtransactionswithintheCustomerbusinessentity.ManualtransactionsaresignificantlyfasterthanautomatictransactionsbecausetheydonotrequireanyinterprocesscommunicationwiththeMicrosoftDistributedTransactionCoordinator(DTC).
Figure11showshowtodecidewhethertousemanualtransactionsorautomatictransactions.DuetotheoverheadofCOM+transactions,therecommendedapproachistopushthetransactiontothedatabaseandcontrolthetransactionalbehaviorinstoredprocedureswherepossible.

Figure11.Decidinghowtoimplementtransactions
NoteIfyouarecallingfromanASP.NET-basedclient,andthereisnobusinessprocesstoinitiatethetransaction,youmaybetemptedtostartthetransactionintheASP.NETcode-behind.Thisisnotagooddesign;youshouldneverinitiateatransactionfromanASP.NET-basedclient.Instead,separatethepresentationofthedatafromthebusinessprocess.Performanceisalsoanissueduetoissuessuchasnetworklatency,becausethisisthemostcommonlayertobephysicallydeployedonanothertier.

RecommendationsforUsingManualTransactionsinDataAccessLogicComponents

Whenyouimplementmanualtransactionsindataaccesslogiccomponents,considerthefollowingrecommendations:
·Wherepossible,performyourprocessinginstoredprocedures.UsetheTransact-SQLstatementsBEGINTRANSACTION,ENDTRANSACTION,andROLLBACKTRANSACTIONtocontroltransactions.Foracodeexample,see"HowToPerformTransactionsWithTransact-SQL"inthe.NETDataAccessArchitectureGuide.
·Ifyouarenotusingstoredprocedures,andthedataaccesslogiccomponentswillnotbecalledfromabusinessprocess,youcancontroltransactionsprogrammaticallybyusingADO.NET.Foracodeexample,see"HowtoCodeADO.NETManualTransactions"inthe.NETDataAccessArchitectureGuide.

RecommendationsforUsingAutomaticTransactionsinDataAccessLogicComponents

DespitetheoverheadassociatedwithCOM+transactions,automatictransactionsprovideasimplerprogrammingmodelthanmanualtransactions,andarenecessarywhenyourtransactionsspanmultipledistributeddatasourcesastheyworkinconjunctionwiththeDTC.Ifyouimplementautomatictransactionsindataaccesslogiccomponents,considerthefollowingrecommendations:
·TheDataAccessLogicComponentmustinheritfromtheServicedComponentclassintheSystem.EnterpriseServicesnamespace.NotethatanyassemblyregisteredwithCOM+servicesmusthaveastrongname.Formoreinformationaboutstrong-namedassemblies,seeCreatingandUsingStrong-NamedAssemblies.
·AnnotatetheDataAccessLogicComponentwiththeTransaction(TransactionOption.Supported)attributesothatyoucanperformreadandwriteoperationsinthesamecomponent.Thisoptionavoidstheoverheadoftransactionswheretheyarenotrequired—unlikeTransaction(TransactionOption.Required),whichalwaysrequiresatransaction.
ThefollowingcodesampleshowshowtosupportautomatictransactionsinaDataAccessLogicComponentclass:usingSystem.EnterpriseServices;
[Transaction(TransactionOption.Supported)]
publicclassCustomerDALC:ServicedComponent
{
...
}

Ifyouuseautomatictransactions,yourdataaccesslogiccomponentsshouldvoteintransactionstoindicatewhethertheoperationsucceededorfailed.Tovoteimplicitly,annotateyourmethodsbyusingtheAutoCompleteattributeandthrowanexceptioniftheoperationfails.Tovoteexplicitly,calltheSetCompleteorSetAbortmethodontheContextUtilclass.
Formoreinformationaboutautomatictransactions,see"UsingAutomaticTransactions"inthe.NETDataAccessArchitectureGuide.

UsingAutomaticTransactionsinBusinessEntityComponents

Ifyouimplementcustombusinessentitycomponentsthathavebehaviors,youcanuseautomatictransactionstospecifythetransactionalbehavioroftheseobjects.Therecommendationsforusingautomatictransactionstospecifythetransactionalbehaviorofbusinessentitycomponentsarethesameasthepreviouslylistedrecommendationsforimplementingautomatictransactionsindataaccesslogiccomponents.
NoteIftheBusinessEntityComponentdoesnotcontainanybusinesslogicthatrequiresittovoteinthetransaction,itcanignorethetransactioncontextaltogether.ThecustomBusinessEntityComponentdoesnotneedtoinheritfromServicedComponent;thetransactioncontextwillstillflow,buttheentitycomponentwillignorethecontext.

Validations

Youcanperformdatavalidationatmanytiersinyourapplication.Differenttypesofvalidationareappropriateineachtier:
·Theclientapplicationcanvalidatebusinessentitydatalocally,beforethedataissubmitted.
·BusinessprocessescanvalidatebusinessdocumentsasthedocumentsarereceivedbyusinganXSDschema.
·Dataaccesslogiccomponentsandstoredprocedurescanvalidatedatatoensurereferentialintegrityandtoenforceconstraintsandnontrivialbusinessrules.
Therearetwogeneralkindsofvalidation:
·Point-in-timevalidation.Thisisvalidationthatisperformedataspecificpointintime.Forexample,abusinessprocessvalidatesanXMLdocumentwhenthedocumentisreceived.
·Continuousvalidation.Thisisvalidationthatisperformedonanongoingbasisatmanydifferentlevelsinyourapplication.Examplesofcontinuousvalidationincludethefollowing:
·Userinterfacescanspecifymaximumfieldlengthstopreventtheuserfromenteringstringsthataretoolong.
·DataSetscanspecifythemaximumlengthofdatacolumns.
·Custombusinessentitycomponentscanperformrangechecks,lengthchecks,non-nullchecks,andothersimpletestsonentitydata.
·Dataaccesslogiccomponents,storedprocedures,andthedatabaseitselfcanperformsimilarteststoensurethatdataisvalidbeforeitissavedinthedatabase.
Attimes,youmaywanttoimplementanout-of-bandaggregatororatransformerprocess.Thisapproachmaybeusefulifthevalidationsandtransformationschangeoften,butitincursaperformancepenalty.Forexample,ifanISVwantedtousethesamecomponentstosupporttwoversionsofadatabaseschema,youcouldcreateaseparatecomponenttoperformvalidationandtransformationsbetweenthetwodatabaseschemaversions.

HowtoValidateXMLbyUsinganXSDSchema

TovalidateanXMLdocumentagainstanXSDschema,takethefollowingsteps:
1.CreateanXmlValidatingReaderobjectasawrapperaroundanXmlTextReaderobject,asshowninthefollowingcode:2.'CreateanXmlValidatingReaderobject,toreadandvalidateProduct.xml
3.XmlTextReadertr=newXmlTextReader("Product.xml");
4.XmlValidatingReadervr=newXmlValidatingReader(tr);

5.Specifythetypeofvalidationrequired,byusingtheValidationTypeenumeration.The.NETFrameworksupportsthreetypesofXMLvalidation:
·Documenttypedefinitions(DTDs);specifyValidationType.DTD
·MicrosoftXMLdata-reduced(XDR)schemas;specifyValidationType.XDR
·W3C-standardXSDschemas;specifyValidationType.Schema
ThefollowingcodeshowstheuseoftheValidationTypeenumeration:vr.ValidationType=ValidationType.Schema;'SpecifyXSDschema
validation

6.Registeravalidationevent-handlermethod,asshowninthefollowingcode:7.vr.ValidationEventHandler+=newValidationEventHandler(MyHandlerMethod);
8.Provideanimplementationforthevalidationevent-handlermethod,asshowninthefollowingcode:9.publicvoidMyHandlerMethod(objectsender,ValidationEventArgse)
10.{
11.Console.WriteLine("ValidationError:"+e.Message);
12.}

13.Readandvalidatethedocument,asshowninthefollowingcode.Validationerrorsarepickedupbythevalidationevent-handlermethod.14.try
15.{
16.while(vr.Read())
17.{
18.//ProcesstheXMLdata,asappropriate...
19.}
20.}
21.catch(XmlExceptionex)
22.{
23.Console.WriteLine("XmlException:"+ex.Message);
24.}
25.vr.Close();

HowtoValidateDatainPropertyAccessorsinBusinessEntityComponents

Thefollowingcodefragmentshowshowtoperformsimplevalidationinpropertyaccessorsinacustomentity.Ifthevalidationtestfails,youcanthrowanexceptiontoindicatethenatureoftheproblem.Youcanalsouseregularexpressionswithinyoursetpropertyaccessorstovalidatespecificdataandformats.publicclassProductDALC
{
…
publicshortReorderLevel
{
get{returnreorderLevel;}
}
set
{
if(value<0)
{
thrownewArgumentOutOfRangeException("ReorderLevelcannotbe
negative.");
}
reorderLevel=value;
}
//PlusothermembersintheProductDALCclass...
}

ExceptionManagement

Whenerrorsoccurin.NETapplications,thegeneraladviceistothrowexceptionsratherthanreturnerrorvaluesfromyourmethods.Thisadvicehasimplicationsforthewayyouwritedataaccesslogiccomponentsandbusinessentitycomponents.Therearetwogeneralkindsofexceptionsthatwilloccur:
·Technicalexceptions,whichinclude:
·ADO.NET
·Connectiontodatabase
·Resources(suchasdatabase,networkshare,andMessageQueuing)areunavailable
·Businesslogicexceptions,whichinclude:
·Validationerrors
·Errorsinstoredproceduresthatimplementbusinesslogic

RecommendationsforManagingExceptionsinaDataAccessLogicComponent

Dataaccesslogiccomponentsshouldpropagateexceptions,andshouldwrapexceptiontypesonlyifdoingsomakestheexceptioneasierfortheclienttomanage.Wrappingtheexceptionsintwomainexceptiontypes(technicalandbusiness)helpsexceptionhandlingstructureandexceptionpublishinglogicforthepotentiallydiversecallers.
Yourapplicationshouldpublishexceptioninformation.TechnicalexceptionscanbepublishedtoalogthatismonitoredbyadministratorsorbyaWindowsManagementInstrumentation(WMI)monitoringtoollikeMicrosoftOperationsManager.Businessexceptionscanbepublishedtoanapplication-specificlog.Ingeneral,allowtheexceptionstopropagatefromyourDataAccessLogicComponentandbepublishedbythecallersothatyouhavetheentirecontextoftheexception.
Thefollowingexampleillustratestheserecommendations:publicclassCustomerDALC
{
publicvoidUpdateCustomer(DatasetaCustomer)
{
try
{
//Updatethecustomerinthedatabase...
}
catch(SqlExceptionse)
{
//Catchtheexceptionandwrap,andrethrow
thrownewDataAccessException("Databaseisunavailable",se);
}
finally
{
//Cleanupcode
}
}
}

RecommendationsforManagingExceptionsinBusinessEntityComponents

Businessentitycomponentsshouldpropagateexceptionstocallers.Businessentitycomponentsmayalsoraiseexceptionsiftheyareperformingvalidation,orifthecallertriestoperformanoperationwithoutprovidingalltherequireddatafortheoperation.
Thefollowingexampleillustrateshowabusinessentitycomponentcanraiseanexception.Inthisexample,theUpdatemethodthrowsanexceptionifthecustomer'sfirstnameisnotprovided:publicclassCustomerEntity
{
publicvoidUpdate()
{
//Checkthattheuserhasprovidedtherequireddata.Inthiscasea
firstnamefor
//thecustomer
if(FirstName=="")
{
//Throwanewapplicationexceptionthatyouhavedefined
thrownewMyArgumentException("YoumustprovideaFirstName.);
}
...
}
}

Formoreinformationaboutdealingwithexceptionsin.NETapplications,seeExceptionManagementin.NET.YoucaninherityourcustomtechnicalexceptionsandcustombusinessexceptionsfromtheApplicationExceptionclassortheBaseApplicationExceptionclassprovidedintheExceptionManagementApplicationBlock.

AuthorizationandSecurity

Thissectionexplainshowsecurityappliestoyourdataaccesslogiccomponentsandyourbusinessentitycomponents.The.NETcommonlanguageruntimeusespermissionsobjectstoimplementitsmechanismforenforcingrestrictionsonmanagedcode.Therearethreekindsofpermissionsobjects,eachwithaspecificpurpose:
·Codeaccesssecurity.Thesepermissionsobjectsareusedtoprotectresourcesandoperationsfromunauthorizeduse.
·Identity.Thesepermissionsobjectsspecifytherequiredidentitycharacteristicsthatanassemblymusthaveinordertorun.
·Role-basedsecurity.Thesepermissionsobjectsprovideamechanismfordiscoveringwhetherauser(ortheagentactingontheuser'sbehalf)hasaparticularidentityorisamemberofaspecifiedrole.ThePrincipalPermissionobjectistheonlyrole-basedsecuritypermissionsobject.
ManagedcodecandiscovertheidentityortheroleofaprincipalbyusingaPrincipalobject,whichcontainsareferencetoanIdentityobject.Itmightbehelpfultocompareidentityandprincipalobjectstofamiliarconceptslikeuserandgroupaccounts.Inthe.NETFramework,identityobjectsrepresentusers,whereasrolesrepresentmembershipsandsecuritycontexts.Theprincipalobjectencapsulatesbothanidentityobjectandarole.Applicationsinthe.NETFrameworkgrantrightstotheprincipalobjectbasedonitsidentityor,morecommonly,itsrolemembership.
Formoreinformationaboutpermissionsandsecurityin.NET,seeKeySecurityConcepts.

RecommendationsforSecurityinDataAccessLogicComponents

Dataaccesslogiccomponentsaredesignedtobeusedbyotherapplicationcomponents,andarethelastplaceinyourapplicationcodewhereyoucanimplementsecuritybeforethecallerhasaccesstoyourdata.
Often,dataaccesslogiccomponentscanrelyonthesecuritycontextsetbythecaller.However,therearesomesituationswheretheDataAccessLogicComponentshouldperformitsownauthorizationcheckstodeterminewhetheraprincipalisallowedtoperformarequestedaction.Authorizationoccursafterauthenticationandusesinformationabouttheprincipal'sidentityandrolestodeterminewhatresourcestheprincipalcanaccess.
PerformauthorizationchecksattheDataAccessLogicComponentlevelifyouneedto:
·Sharedataaccesslogiccomponentswithdevelopersofbusinessprocessesthatyoudonotfullytrust
·Protectaccesstopowerfulfunctionsexposedbythedatastores
Afteryoudefineidentityandprincipalobjects,therearethreedifferentwaystoperformrole-basedsecuritychecks:
·UsethePrincipalPermissionobjecttoperformimperativesecuritychecks.
·UsethePrincipalPermissionAttributeattributetoperformdeclarativesecuritychecks.
·UsethepropertiesandtheIsInRolemethodinthePrincipalobjecttoperformexplicitsecuritychecks.
ThefollowingcodesampleshowshowtousePrincipalPermissionAttributetospecifyadeclarativerole-basedsecuritycheckonamethodinaDataAccessLogicComponentclass:usingSystem;
usingSystem.Security.Permissions;
publicclassCustomerDALC
{
publicCustomerDALC()
{
}
//UsePrincipalPermissionAttributetodemandthatthecallerofthis
method
//hasanidentitynamed"MyUser",andbelongstothe"Administrator"role.
[PrincipalPermissionAttribute(SecurityAction.Demand,
Name="MyUser",Role="Administrator")]
publicvoidDeleteCustomer(stringcustomerID)
{
//Deletecustomercodehere
}
}

Thefollowingcodeshowshowtocreateaprincipalobjectthathastherequiredidentityandrole,sothatyoucancalltheDeleteCustomermethodonaCustomerDALCobject:usingSystem;
usingSystem.Security.Principal;
usingSystem.Threading;
publicclassMainClass
{
publicstaticintMain(string[]args)
{
Console.Write("UserName:");
stringUserName=Console.ReadLine();
Console.Write("Password:");
stringPassword=Console.ReadLine();
if(Password=="password"&&UserName=="MyUser")
{
//Createagenericidentitywiththename"MyUser"
GenericIdentityMyIdentity=newGenericIdentity("MyUser");
//Createroles
String[]MyString={"Administrator","User"};
//Createagenericprincipal
GenericPrincipalMyPrincipal=newGenericPrincipal(MyIdentity,
MyString);
//Setthisthread'scurrentprincipal,foruseinrole-basedsecurity
Thread.CurrentPrincipal=MyPrincipal;
}
//CreateaCustomerDALCobject,andtrytocallitsDeleteCustomer
method.
//Thiswillonlysucceedifthecurrentprincipal'sidentityandrole
areOK.
CustomerDALCc=newCustomerDALC();
c.DeleteCustomer("VINET");
}
}

WindowsAuthentication

Ideally,youshoulduseWindowsAuthentication,ratherthanusingSQLServerAuthentication,whenyouconnecttothedatabase.However,youshoulduseserviceaccountsandavoidimpersonatingthroughtothedatabase,becausethiswillimpedeconnectionpooling.Connectionpoolingrequiresidenticalconnectionstrings;ifyoutrytoopenthedatabasebyusingdifferentconnectionstrings,youwillcreateseparateconnectionpools,whichwilllimitscalability.
FormoreinformationaboutWindowsAuthenticationandconnectionpooling,seethe"ManagingDatabaseConnections"sectioninthe.NETDataAccessArchitectureGuide.

SecureCommunicationRecommendations

Toachievesecurecommunicationbetweencallingapplicationsanddataaccesslogiccomponents,considerthefollowingrecommendations:
·Ifyourdataaccesslogiccomponentsarecalledoverthewirefromdiversetiers,andtheexchangeinvolvessensitiveinformationthatneedstobeprotected,useDistributedComponentObjectModel(DCOM),SecureSocketsLayer(SSL),orSecureInternetProtocol(IPSec)securecommunicationtechnologies.
·Ifdataisstoredencryptedinadatabase,dataaccesslogiccomponentsareusuallyresponsibleforencryptinganddecryptingthedata.Iftheriskofexposingtheinformationishigh,stronglyconsidersecuringthecommunicationchanneltoandfromthedataaccesslogiccomponents.

RecommendationsforSecurityinBusinessEntityComponents

Ifyouimplementyourbusinessentitiesasdatastructures(suchasXMLorDataSets),youdonotneedtoimplementsecuritychecks.However,ifyouimplementyourbusinessentitiesascustombusinessentitycomponentswithCRUDoperations,considerthefollowingrecommendations:
·Iftheentitiesareexposedtobusinessprocessesthatyoudonotfullytrust,implementauthorizationchecksinthebusinessentitycomponentsandinthedataaccesslogiccomponents.Ifyoudoimplementchecksatbothlevels,however,youmayencounterthemaintenanceissueofkeepingthesecuritypoliciessynchronized.
·Businessentitycomponentsshouldnotdealwithcommunicationsecurityordataencryption.LeavethesetaskstothecorrespondingDataAccessLogicComponent.

Deployment

Thissectionprovidesrecommendationstohelpyoudecidehowtodeploydataaccesslogiccomponentsandbusinessentitycomponents.

DeployingDataAccessLogicComponents

Therearetwowaystodeploydataaccesslogiccomponents:
·Deploydataaccesslogiccomponentstogetherwiththebusinessprocessobjects.Thisdeploymentmethodprovidesoptimumperformancefordatatransfers,andhasseveraladditionaltechnicalbenefits:
·Transactionscanflowseamlesslybetweenthebusinessprocessobjectsandthedataaccesslogiccomponents.However,transactionsdonotflowseamlesslyacrossremotingchannels.Intheremotingscenario,youneedtoimplementtransactionsbyusingDCOM.Furthermore,ifthebusinessprocessandtheDataAccessLogicComponentwereseparatedbyafirewall,youwouldrequirefirewallportsopenbetweenbothphysicaltierstoenableDTCcommunication.
·Deployingbusinessprocessobjectsanddataaccesslogiccomponentstogetherreducesthenumberoftransactionfailurenodes.
·Thesecuritycontextflowsautomaticallybetweenthebusinessprocessobjectsandthedataaccesslogiccomponents.Thereisnoneedtosetprincipalobjects.
·Deploydataaccesslogiccomponentstogetherwiththeuser-interfacecode.DataaccesslogiccomponentsaresometimesuseddirectlyfromUIcomponentsandUIprocesscomponents.ToincreaseperformanceinWebscenarios,youcandeploydataaccesslogiccomponentstogetherwiththeUIcode;thisdeploymentmethodenablestheUIlayertotakeadvantageofdatareaderstreamingforoptimumperformance.However,ifyoudoconsiderthisdeploymentmethod,bearinmindthefollowing:
·AcommonreasonfornotdeployingdataaccesslogiccomponentstogetherwithUIcodeistopreventdirectnetworkaccesstoyourdatasourcesfromyourWebfarms.
·IfyourWebfarmisdeployedinaDMZscenario,firewallportsmustbeopenedtoaccessSQLServer.IfyouareusingCOM+transactions,additionalfirewallportsmustbeopenedforDTCcommunication.Formoreinformation,seethe.NETDataAccessArchitectureGuide.

DeployingBusinessEntities

Businessentitiesareusedatmanydifferenttiersinyourapplication.Dependingonhowyouimplementyourbusinessentities,youmayneedtodeploythemtomultiplelocationsifyourapplicationspansphysicaltiers.Thefollowinglistdescribeshowtodeploybusinessentitiesindifferentimplementationscenarios:
·DeployingBusinessEntitiesimplementedastypedDataSets.ThetypedDataSetclassmustbeaccessedbytheDataAccessLogicComponentandbythecallingapplication.Therefore,therecommendationistodefinetypedDataSetclassesinacommonassemblytobedeployedonmultipletiers.
·DeployingBusinessEntitiesimplementedascustombusinessentitycomponents.ThecustomentityclassmayneedtobeaccessedbytheDataAccessLogicComponent,dependingonhowyoudefinedthemethodsignaturesintheDataAccessLogicComponent.FollowthesamerecommendationasfortypedDataSetsbydefiningcustomentityclassesinacommonassemblytobedeployedonmultipletiers.
·DeployingBusinessEntitiesimplementedasgenericDataSetsorXMLstrings.GenericDataSetsandXMLstringsdonotrepresentaseparatedatatype.Therearenodeploymentissuesforbusinessentitiesimplementedintheseformats.

Appendix

HowtoDefineaDataAccessLogicComponentClass
HowtoUseXMLtoRepresentCollectionsandHierarchiesofData
HowtoApplyaStyleSheetProgrammaticallyina.NETApplication
HowtoCreateaTypedDataSet
HowtoDefineaBusinessEntityComponent
HowtoRepresentCollectionsandHierarchiesofDatainaBusinessEntityComponent
HowtoBindBusinessEntityComponentstoUser-InterfaceControls
HowtoExposeEventsinaBusinessEntityComponent
HowtoSerializeBusinessEntityComponentstoXMLFormat
HowtoSerializeBusinessEntityComponentstoSOAPFormat
HowtoSerializeBusinessEntityComponentstoBinaryFormat

HowtoDefineaDataAccessLogicComponentClass

ThecodethatfollowsisasampledefinitionofaclassnamedCustomerDALC,whichistheDataAccessLogicComponentclassforCustomerbusinessentities.TheCustomerDALCclassimplementstheCRUDoperationsfortheCustomerbusinessentityandprovidesadditionalmethodstoencapsulatebusinesslogicforthisobject.publicclassCustomerDALC
{
privatestringconn_string;
publicCustomerDALC()
{
//Acquiretheconnectionstringfromasecureorencryptedlocation
//andassigntoconn_string
}
publicCustomerDataSetGetCustomer(stringid)
{
//CodetoretrieveatypedDataSetcontainingCustomerdata
}
publicstringCreateCustomer(stringname,
stringaddress,stringcity,stringstate,
stringzip)
{
//Codetocreateanewcustomerinthedatabase,basedonthescalar
//parameterspassedintothismethod.
//ReturnthecustomerIDfromthismethod.
}
publicvoidUpdateCustomer(CustomerDataSetupdatedCustomer)
{
//Codetoupdatethedatabase,basedontheCustomerdatasentinasa
parameter
//oftypeCustomerDataSet
}
publicvoidDeleteCustomer(stringid)
{
//CodetodeletethecustomerwiththespecifiedID
}
publicDataSetGetCustomersWhoPurchasedProduct(intproductID)
{
//CodetoretrievecustomersusingagenericDataSet,becausethis
methodisnot
//retrievingalltheinformationassociatedwithacustomer
}
}

HowtoUseXMLtoRepresentCollectionsandHierarchiesofData

ThefollowingexampleshowshowtorepresentcollectionsandhierarchiesofdatainanXMLdocument.TheXMLdocumentrepresentsasingleordermadebyacustomer;notethatthe<OrderDetails>elementholdsacollectionoforderdetailinformationfortheorder.<Orderxmlns="urn:aUniqueNamespace">
<OrderID>10248</OrderID>
<CustomerID>VINET</CustomerID>
<OrderDate>1996-07-04</OrderDate>
<ShippedDate>1996-07-16</ShippedDate>
<OrderDetails>
<OrderDetail>
<ProductID>11</ProductID>
<UnitPrice>14.00</UnitPrice>
<Quantity>12</Quantity>
</OrderDetail>
<OrderDetail>
<ProductID>42</ProductID>
<UnitPrice>9.80</UnitPrice>
<Quantity>10</Quantity>
</OrderDetail>
<OrderDetail>
<ProductID>72</ProductID>
<UnitPrice>34.80</UnitPrice>
<Quantity>5</Quantity>
</OrderDetail>
</OrderDetails>
</Order>

HowtoApplyaStyleSheetProgrammaticallyina.NETApplication

Toapplyastylesheetprogrammaticallyina.NETapplication,takethefollowingsteps:
1.ImporttheSystem.Xml.Xslnamespaceasshowninthefollowingcode.TheSystem.Xml.XslnamespacecontainstheXSLTtransformationclassesinthe.NETFrameworkclasslibrary.2.usingSystem.Xml.Xsl;
3.CreateanXslTransformobjectasshowninthefollowingcode:4.XslTransformstylesheet=newXslTransform();
5.LoadtherequiredstylesheetintotheXslTransformobjectasshowninthefollowingcode:6.stylesheet.Load("MyStylesheet.xsl");
7.CalltheTransformmethodontheXslTransformobjectasshowninthefollowingcode.CallingtheTransformmethodspecifiesthenamesoftheXMLsourcedocumentandtheresultdocument.8.stylesheet.Transform(sourceDoc,resultDoc);

HowtoCreateaTypedDataSet

YoucanusetypedDataSetstorepresentbusinessentities.ThereareseveralwaystocreateatypedDataSet:
·FromadataadapterwithinMicrosoftVisualStudio®.NET
·FromanXSDschemafilewithinVisualStudio.NET
·Fromthe.NETFrameworkcommandpromptwindowbyusingtheXSDSchemaDefinitionTool(xsd.exe)
NoteItisalsopossibletodefineatypedDataSetprogrammaticallybyinheritingfromtheDataSetanddefiningmethods,properties,andnestedclassestorepresentthestructureoftheDataSet.TheeasiestwaytodothisistocreateatypedDataSetbyusingoneoftheproceduresthatfollow,andthenusethistypedDataSetclassasthebasisforyourowntypedDataSetclassesinthefuture.

CreatingaTypedDataSetbyUsingaDataAdapter

TocreateatypedDataSetbyusingadataadapter,followthesesteps:
1.InVisualStudio.NET,addadataadaptertoyourformorcomponent.InthedataadapterConfigurationWizard,specifyconnectioninformationforthedataadapter.AlsospecifySQLstringsorstoredproceduresfortheSelect,Insert,Update,andDeletecommandsforyourdataadapter,asappropriate.
2.IntheComponentDesigner,right-clicktheDataAdapterobject,andthenclickGenerateDataSet.
3.IntheGenerateDataSetdialogbox,clickNew,typeanameforthenewDataSetclass,andthenclickOK.
4.ToverifythatthetypedDataSethasbeencreated,inSolutionExplorer,clicktheShowAllFilesbutton.ExpandthenodefortheXSDschemafile,andverifythatthereisacodefileassociatedwiththeXSDschema.ThecodefiledefinesthenewtypedDataSetclass.

CreatingaTypedDataSetfromanXSDSchemaFile

TocreateatypedDataSetfromanXSDschemafilebyusingVisualStudio.NET,followthesesteps:
1.InVisualStudio.NET,createanewprojectoropenanexistingproject.
2.AddanexistingXSDschematotheproject,orcreateanewXSDschemaintheComponentDesigner.
3.InSolutionExplorer,double-clicktheXSDschemafiletoviewtheXSDschemaintheComponentDesigner.
4.SelecttheprimaryXSDschemaelementintheComponentDesigner.
5.OntheSchemamenu,clickGenerateDataSet.
6.ToverifythatthetypedDataSethasbeencreated,inSolutionExplorer,clicktheShowAllFilesbutton.ExpandthenodefortheXSDschemafile,andverifythatthereisacodefileassociatedwiththeXSDschema.ThecodefiledefinesthenewtypedDataSetclass.

CreatingaTypedDataSetbyUsingtheXSDSchemaDefinitionTool(xsd.exe)

TheXMLSchemaDefinitiontoolcangenerateatypedDataSetfromanXSDschemafile,anXDRschemafile,oranXMLinstancedocument.ThefollowingcommandusesanXSDschemafilenamedXsdSchemaFile.xsdtogenerateatypedDataSetinaVisualC#sourcefilenamedXsdSchemaFile.csinthecurrentdirectory:xsd/dataset/language:C#XsdSchemaFile.xsd
Formoreinformation,seeGeneratingaStronglyTypedDataSet.

HowtoDefineaBusinessEntityComponent

ThefollowingexampleshowshowtodefineacustomentityclassfortheProductbusinessentity:publicclassProductEntity
{
//Privatefields,toholdthestateoftheProductentity
privateintproductID;
privatestringproductName;
privatestringquantityPerUnit;
privatedecimalunitPrice;
privateshortunitsInStock;
privateshortunitsOnOrder;
privateshortreorderLevel;
//Publicproperties,toexposethestateoftheentity
publicintProductID
{
get{returnproductID;}
set{productID=value;}
}
publicstringProductName
{
get{returnproductName;}
set{productName=value;}
}
publicstringQuantityPerUnit
{
get{returnquantityPerUnit;}
set{quantityPerUnit=value;}
}
publicdecimalUnitPrice
{
get{returnunitPrice;}
set{unitPrice=value;}
}
publicshortUnitsInStock
{
get{returnunitsInStock;}
set{unitsInStock=value;}
}
publicshortUnitsOnOrder
{
get{returnunitsOnOrder;}
set{unitsOnOrder=value;}
}
publicshortReorderLevel
{
get{returnreorderLevel;}
set{reorderLevel=value;}
}
//Methodsandpropertiestoperformlocalizedprocessing
publicvoidIncreaseUnitPriceBy(decimalamount)
{
unitPrice+=amount;
}
publicshortUnitsAboveReorderLevel
{
get{return(short)(unitsInStock-reorderLevel);}
}
publicstringStockStatus
{
get
{
return"Instock:"+unitsInStock+",onorder:"+unitsOnOrder;
}
}
}

HowtoRepresentCollectionsandHierarchiesofDatainaBusinessEntityComponent

ThefollowingexampleshowshowtodefineacustomentityclassfortheOrderbusinessentity.Eachordercomprisesmanyorderitems;theseorderitemsarestoredinaDataSetintheOrderEntityclass.publicclassOrderEntity
{
//Privatefields,toholdtheorderinformation
privateintorderID;
privatestringcustomerID;
privateDateTimeorderDate;
privateDateTimeshippedDate;
//Privatefield,toholdtheorderdetailsinformation
privateDataSetorderDetails;
//Publicproperties,toexposetheorderinformation
publicintOrderID
{
get{returnorderID;}
set{orderID=value;}
}
publicstringCustomerID
{
get{returncustomerID;}
set{customerID=value;}
}
publicDateTimeOrderDate
{
get{returnorderDate;}
set{orderDate=value;}
}
publicDateTimeShippedDate
{
get{returnshippedDate;}
set{shippedDate=value;}
}
//Publicproperty,toexposetheorderdetailsinformation
publicDataSetOrderDetails
{
get{returnorderDetails;}
set{orderDetails=value;}
}
//Additionalmethod,tosimplifyaccesstoorderdetailsinformation
publicboolIsProductOrdered(intproductID)
{
//PrimarykeycolumnmustbedefinedinDataTable
DataRowrow=orderDetails.Tables[0].Rows.Find(productID);
if(row!=null)
returntrue;
else
returnfalse;
}
//Additionalproperty,tosimplifyaccesstoorderdetailsinformation
publicintNumberOfOrderItems
{
get
{
returnorderDetails.Tables[0].Rows.Count;
}
}
}

NotethefollowingpointsconcerningtheOrderEntityclass:
·Theclasscontainsprivatefieldstoholdinformationabouttheorder.ThereisalsoaprivateDataSetfield,toholdadditionaldetailsabouttheorder.TheDataAccessLogicComponentwillpopulateallthesefieldswhenitcreatestheOrderEntityobject.
·Theclasshaspublicpropertiestoexposeinformationabouttheorder.ThereisalsoapropertytoexposetheDataSet,toenablethecallingapplicationtoaccesstheorderdetails.
·Theclasshasanadditionalmethodandpropertytoprovidesimplifiedaccesstoorderdetails:
·TheIsProductOrderedmethodreceivesaProductIDparameterandreturnsaBooleanvaluetoindicatewhetherthisproductappearsintheorder.
·TheNumberOfOrderItemspropertyindicatesthenumberoforderlinesintheorder.

HowtoBindBusinessEntityComponentstoUser-InterfaceControls

Youcanbinduser-interfacecontrolstocustomentitiesinWindowsFormsandinASP.NETapplications.Therearetwopossiblescenarios:
·Bindingasinglebusinessentitytouser-interfacecontrols.ThefollowingcodesampleshowshowyoucangetanOrderEntityobjectfromtheOrderDALCobjectandbindtheOrderEntityobjecttocontrolsinaWindowsForm.Whentheuserchangesvaluesinthesecontrols,thedataintheunderlyingOrderEntityobjectisalsochangedautomatically.·//CreateanOrderDALCobject.
·OrderDALCdalcOrder=newOrderDALC();
·
·//UsedalcOrdertogetanOrderEntityobjectfororderID10248.
·//ThiscodeassumestheOrderDALCclasshasamethodnamedGetOrder(),
·which
·//returnsanOrderEntityobjectforaparticularorderID.
·OrderEntityorder=dalcOrder.GetOrder(10248);
·
·//BindtheOrderIDpropertyoftheOrderEntitytoaTextBoxcontrol.
·textBox1.DataBindings.Add("Text",order,"OrderID");
·
·//BindtheCustomerIDpropertyoftheOrderEntitytoanotherTextBox
·control.
·textBox2.DataBindings.Add("Text",order,"CustomerID");
·
·//BindtheOrderDatepropertyoftheOrderEntitytoaDatePickercontrol.
·dateTimePicker1.DataBindings.Add("Value",order,"OrderDate");
·
·//BindtheShippedDatepropertyoftheOrderEntitytoanotherDatePicker
·control.
·dateTimePicker2.DataBindings.Add("Value",order,"ShippedDate");
·
·//BindtheOrderDetailsDataSetoftheOrderEntitytoaDataGridcontrol.
·//TheDataGriddisplayseachDataRowoftheDataSetinaseparaterowin
·thegrid.
·dataGrid1.DataSource=order.OrderDetails.Tables[0].DefaultView;

Whenyouareready,youcanpassthemodifiedOrderEntityobjectbacktotheOrderDALCsothatthedatacanbesavedinthedatabase,asshowninthefollowingcode.//SavetheOrderEntityobjectbacktothedatabase,viadalcOrder.
//ThiscodeassumestheOrderDALCclasshasamethodnamedUpdateOrder(),
which
//receivesanOrderEntityparameterandupdatestheappropriateentryin
thedatabase
dalcOrder.UpdateOrder(order);

·BindingacollectionofbusinessentitiestoaDataGridcontrol.ThefollowingcodesampleshowshowtogetanarrayofOrderEntityobjectsfromtheOrderDALCandthenbindthearraytoaDataGridcontrolinaWindowsForm.TheDataGriddisplayseacharrayelement(thatis,eachOrderEntityobject)inaseparaterowinthegrid.·//CreateanOrderDALCobject.
·OrderDALCdalcOrder=newOrderDALC();
·
·//UsedalcOrdertogetanarrayofOrderEntityobjectsforcustomer
·"VINET".
·//ThiscodeassumestheOrderDALCclasshasamethodnamed
·GetOrdersForCustomer(),
·//whichreturnsanarrayofOrderEntityobjectsforaparticular
·customer.
·OrderEntity[]orderEntities=dalcOrder.GetOrdersForCustomer("VINET");
·
·//BindthearraytoaDataGridcontrol.
·dataGrid1.DataSource=orderEntities;

Whenyouareready,youcanpassthemodifiedarraybacktotheOrderDALCsothatthedatacanbesavedinthedatabase,asshowninthefollowingcode://SavetheOrderEntityobjectsbacktothedatabase,viadalcOrder.
//ThiscodeassumesOrderDALChasamethodnamedUpdateOrders(),which
takesanarray
//ofOrderEntityobjectsandupdatestheappropriateentriesinthe
database.
dalcOrder.UpdateOrders(orderEntities);

HowtoExposeEventsinaBusinessEntityComponent

Customentitiescanraiseeventswhenthebusinessentitystateismodified.Theseeventsareusefulforrichclient,user-interfacedesignbecausedatacanberefreshedwhereveritisbeingdisplayed.Thefollowingcodesampleshowshowtoraisebusinessentity-relatedeventsintheOrderEntityclass://Defineacommoneventclassforallbusinessentityevents
publicclassEntityEventArgs:EventArgs
{
//Defineeventmembers,toprovideinformationabouttheevent
}
//Defineadelegatespecifyingthesignatureforbusinessentity-related
events
publicdelegatevoidEntityEventHandler(Objectsource,EntityEventArgse);
//DefineacustomEntityclassthatraiseseventswhenthebusinessentity
statechanges
publicclassOrderEntity
{
//Define'before'and'after'eventsforbusinessentitystatechanges
publiceventEntityEventHandlerBeforeChange,AfterChange;
//Privatefields,toholdthebusinessentity'sstate
privateintorderID;
privateintcustomerID;
privateDateTimeorderDate;
privateDateTimeshippedDate;
privateDataSetorderDetails;
//Publicproperties,toexposethebusinessentity'sstate
publicintOrderID
{
get{returnorderID;}
set
{
BeforeChange(this,newEntityEventArgs());//Raisea'before'event
orderID=value;
AfterChange(this,newEntityEventArgs());//Raisean'after'event
}
}
publicintCustomerID
{
get{returncustomerID;}
set
{
BeforeChange(this,newEntityEventArgs());//Raisea'before'event
customerID=value;
AfterChange(this,newEntityEventArgs());//Raisean'after'event
}
}
publicDateTimeOrderDate
{
get{returnorderDate;}
set
{
BeforeChange(this,newEntityEventArgs());//Raisea'before'event
orderDate=value;
AfterChange(this,newEntityEventArgs());//Raisean'after'event
}
}
publicDateTimeShippedDate
{
get{returnshippedDate;}
set
{
BeforeChange(this,newEntityEventArgs());//Raisea'before'event
shippedDate=value;
AfterChange(this,newEntityEventArgs());//Raisean'after'event
}
}
//Additionalmembers,asrequired...
}

Notethefollowingpointsconcerningtheprecedingcode:
·TheEntityEventclassprovidesinformationaboutbusinessentity-relatedevents.TheEntityEventHandlerdelegatespecifiesthesignatureforallbusinessentity-relatedeventsraisedbycustomentityclasses.Thedelegatesignaturefollowstherecommended.NETFrameworkguidelinesforevent-handlerdelegates.Forguidelinesonhowtodefineanduseeventsin.NET,seeEventUsageGuidelines.
·TheOrderEntityclassdefinestwoeventsnamedBeforeChangeandAfterChange.
·ThepropertysettersinOrderEntityraiseaBeforeChangeeventbeforethebusinessentitystateischanged,andanAfterChangeeventafterthebusinessentitystateischanged.

HowtoSerializeBusinessEntityComponentstoXMLFormat

Thissectiondiscussesthefollowingissues:
·UsingXmlSerializertoserializeacustomentityobject
·XMLserializationofobjectsinXMLWebservices
·DefaultXMLformatofaserializedcustomentityobject
·ControllingtheXMLformatofaserializedcustomentityobject

UsingXmlSerializertoSerializeaCustomEntityObject

ThefollowingcodesampleshowshowtousetheXmlSerializerclasstoserializeanOrderEntityobjecttoXMLformat:usingSystem.Xml.Serialization;//Thisnamespacecontainsthe
XmlSerializerclass
...
//CreateanXmlSerializerobject,toserializeOrderEntity-typeobjects
XmlSerializerserializer=newXmlSerializer(typeof(OrderEntity));
//SerializeanOrderEntityobjecttoanXMLfilenamed
"MyXmlOrderEntity.xml"
TextWriterwriter=newStreamWriter("MyXmlOrderEntity.xml");
serializer.Serialize(writer,order);
writer.Close();

SerializingObjectsinXMLWebServices

ThefollowingcodesampleshowshowtowriteanXMLWebservicethatusescustomentityobjects:namespaceMyWebService
{
[WebService(Namespace="urn:MyWebServiceNamespace")]
publicclassOrderWS:System.Web.Services.WebService
{
[WebMethod]
publicOrderEntityGetOrder(intorderID)
{
//CreateanOrderDALCobject.
OrderDALCdalcOrder=newOrderDALC();
//UsedalcOrdertogetanOrderEntityobjectforthespecifiedorder
ID.
//ThiscodeassumestheOrderDALCclasshasamethodnamedGetOrder,
//whichtakesanOrderIDasaparameterandreturnsanOrderEntity
object
//containingallthedataforthisorder.
OrderEntityorder=dalcOrder.GetOrder(10248);
//ReturntheOrderEntityobject.Theobjectwillbeserialized
automatically.
returnorder;
}
[WebMethod]
publicvoidUpdateOrder(OrderEntityorder)
{
//CreateanOrderDALCobject.
OrderDALCdalcOrder=newOrderDALC();
//UsedalcOrdertosavetheOrderEntityobject'sdatatothedatabase.
//ThiscodeassumestheOrderDALCclasshasamethodnamedUpdateOrder,
//whichreceivesanOrderEntityobjectandsavesthedatatothe
database.
dalcOrder.UpdateOrder(order);
}

Notethefollowingpointsconcerningtheprecedingcode:
·TheGetOrdermethodreceivesanorderIDasaparameterandreturnsanOrderEntityobjectthatcontainsthedataforthisorder.
·TheUpdateOrdermethodreceivesanOrderEntityobjectandsavestheobject'sdatatothedatabase.
·IftheclientapplicationinvokestheGetOrderandUpdateOrdermethods,OrderEntityobjectswillautomaticallybeserializedtoXMLformatforthemethodcall.

DefaultXMLFormatofaSerializedCustomEntityObject

ThefollowingXMLdocumentshowsthedefaultXMLserializationformatforOrderEntityobjects:<?xmlversion="1.0"encoding="utf-8"?>
<OrderEntityxmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<OrderID>10248</OrderID>
<CustomerID>VINET</CustomerID>
<OrderDate>1996-07-04T00:00:00.0000000+01:00</OrderDate>
<OrderDetails>...seebelow...</OrderDetails>
<ShippedDate>1996-07-16T00:00:00.0000000+01:00</ShippedDate>
</OrderEntity>

TheprecedingdocumentillustratesthedefaultrulesforXMLserialization:
·TherootelementintheXMLdocumentisthesameastheclassname,OrderEntity.
·Eachpublicproperty(andfield)intheOrderEntityobjectisserializedtoanelementthathasthesamename.
TheOrderDetailspropertyintheOrderEntityclassisaDataSet.DataSetsprovidebuilt-insupportforXMLserialization.TheOrderDetailsDataSetisserializedasfollows:<OrderDetails>
<xs:schemaid="NewDataSet"xmlns=""
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:elementname="NewDataSet"msdata:IsDataSet="true"msdata:Locale="en-
UK">
<xs:complexType>
<xs:choicemaxOccurs="unbounded">
<xs:elementname="OrderDetails">
<xs:complexType>
<xs:sequence>
<xs:elementname="OrderID"type="xs:int"minOccurs="0"/>
<xs:elementname="ProductID"type="xs:int"minOccurs="0"/>
<xs:elementname="UnitPrice"type="xs:decimal"minOccurs="0"
/>
<xs:elementname="Quantity"type="xs:short"minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
<diffgr:diffgramxmlns:msdata="urn:schemas-microsoft-com:xml-msdata"
xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
<NewDataSet>
<OrderDetailsdiffgr:id="OrderDetails1"msdata:rowOrder="0"
diffgr:hasChanges="inserted">
<OrderID>10248</OrderID>
<ProductID>11</ProductID>
<UnitPrice>14</UnitPrice>
<Quantity>12</Quantity>
</OrderDetails>
<OrderDetailsdiffgr:id="OrderDetails2"msdata:rowOrder="1"
diffgr:hasChanges="inserted">
<OrderID>10248</OrderID>
<ProductID>42</ProductID>
<UnitPrice>9.8</UnitPrice>
<Quantity>10</Quantity>
</OrderDetails>
<OrderDetailsdiffgr:id="OrderDetails3"msdata:rowOrder="2"
diffgr:hasChanges="inserted">
<OrderID>10248</OrderID>
<ProductID>72</ProductID>
<UnitPrice>34.8</UnitPrice>
<Quantity>5</Quantity>
</OrderDetails>
</NewDataSet>
</diffgr:diffgram>
</OrderDetails>

NotethefollowingpointsconcerningtheserializationofDataSets:
·The<xs:schema>sectiondescribesthestructureoftheDataSet,includingtables,columnnames,andcolumntypes.
·The<xs:diffgram>sectioncontainsthedataoftheDataSet.Each<OrderDetails>elementrepresentsaseparaterowintheOrderDetailstableintheDataSet.

ControllingtheXMLFormatofaSerializedCustomEntityObject

Youcanuse.NETattributesinyourcustomentityclasstocontrolhowthepropertiesandfieldsareserializedtoXML.ConsiderthefollowingrevisedversionoftheOrderEntityclass:[XmlRoot(ElementName="Order",Namespace="urn:MyNamespace")]
publicclassOrderEntity
{
[XmlAttribute(AttributeName="ID")]
publicintOrderID{...getandsetcode,asbefore...}
[XmlAttribute(AttributeName="CustID")]
publicstringCustomerID{...getandsetcode,asbefore...}
[XmlElement(ElementName="Ordered")]
publicDateTimeOrderDate{...getandsetcode,asbefore...}
publicDataSetOrderDetails{...getandsetcode,asbefore...}
[XmlElement(ElementName="Shipped")
publicDateTimeShippedDate{...getandsetcode,asbefore...}
//Additionalmembers,asrequired...
}

·WhenanOrderEntityobjectisserializedtoXML,itnowhasthefollowingformat:<?xmlversion="1.0"encoding="utf-8"?>
<OrderID="10248"
CustID="VINET"
xmlns="urn:MyNamespace"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Ordered>1996-07-04T00:00:00.0000000+01:00</Ordered>
<OrderDetails>...detailssameasbefore...</OrderDetails>
<Shipped>1996-07-16T00:00:00.0000000+01:00</Shipped>
</Order>

FormoreinformationabouthowtouseattributestocontrolXMLserialization,seeAttributesthatControlXMLSerialization.

HowtoSerializeBusinessEntityComponentstoSOAPFormat

ThefollowingcodesampleshowshowtousetheSoapFormatterclasstoserializeanOrderEntityobjecttoSOAPformat.SOAPserializationalsooccurs(implicitly)whenyoupassanobjecttoorfromanXMLWebservicebyusingtheSOAPprotocol,andwhenyoupassanobjecttoorfromaRemotingserverbyusinganHTTPremotingchannel.Inaddition,youcanspecifySOAPformattingwhenyouusetheTCPremotingchannel.usingSystem.Runtime.Serialization.Formatters.Soap;//Forthe
SoapFormatterclass
...
//CreateaSoapFormatterobject,toserializeOrderEntity-typeobjects
SoapFormatterformatter=newSoapFormatter();
//SerializeanOrderEntityobjecttoaSOAP(XML)filenamed
"MySoapOrderEntity.xml"
FileStreamstream=File.Create("MySoapOrderEntity.xml");
formatter.Serialize(stream,order);
stream.Close();

TouseSOAPserializationforcustomentitycomponents,youmustannotateyourentityclassbyusingtheSerializableattribute,asshowninthefollowingcode:[Serializable]
publicclassOrderEntity
{
//Members,asbefore

IfyouwanttocustomizetheSOAPformatgeneratedduringserialization,yourentityclassmustimplementtheISerializableinterface.YoumustprovideaGetObjectDatamethodfortheSoapFormattertocallduringserialization,andyoumustprovideaspecialconstructorfortheSoapFormattertocalltorecreatetheobjectduringdeserialization.ThefollowingcodedemonstratestheuseoftheISerializableinterface,theGetObjectDatamethod,andthespecialconstructor:usingSystem.Runtime.Serialization;//ForISerializableinterface,and
relatedtypes
...
[Serializable]
publicclassOrderEntity:ISerializable
{
//Serializationfunction,calledbytheSoapFormatterduringserialization
voidISerializable.GetObjectData(SerializationInfoinfo,StreamingContext
ctxt)
{
//AddeachfieldtotheSerializationInfoobject
info.AddValue("OrderID",orderID);
//Additionalcode,asrequired...
}
//Deserializationconstructor,calledbytheSoapFormatterduring
deserialization
publicOrderEntity(SerializationInfoinfo,StreamingContextctxt)
{
//DeserializefromtheSerializationInfoobjecttotheOrderEntity
fields
orderID=(int)info.GetValue("OrderID",typeof(int));
//Additionalcode,asrequired...
}
//Othermembers,asbefore...
}

FormoreinformationaboutcustomizedSOAPserialization,seeBasicSerialization.

HowtoSerializeBusinessEntityComponentstoBinaryFormat

ThefollowingcodesampleshowshowtousetheBinaryFormatterclasstoserializeanOrderEntityobjecttobinaryformat.Binaryserializationalsooccurs(implicitly)whenyoupassanobjecttoorfromaRemotingserverbyusingaTCPremotingchannel.Inaddition,toimproveperformance,youcanspecifybinaryformattingwhenyouusetheHTTPremotingchannel.usingSystem.Runtime.Serialization.Formatters.Binary;//Forthe
BinaryFormatterclass
...
//CreateaBinaryFormatterobject,toserializeOrderEntity-typeobjects
BinaryFormatterformatter=newBinaryFormatter();
//SerializeanOrderEntityobjecttoabinaryfilenamed
"MyBinaryOrderEntity.dat"
FileStreamstream=File.Create("MyBinaryOrderEntity.dat");
formatter.Serialize(stream,order);
stream.Close();

Tousebinaryserializationforcustomentityobjects,youmustannotateyourcustomentityclassbyusingtheSerializableattribute.Tocustomizethebinaryformatgeneratedduringserialization,yourcustomentityclassmustimplementtheISerializableinterface.ThecodingdetailsinbothscenariosarethesameasforSOAPserialization.
Formoreinformationaboutbinaryserialization,seeBinarySerialization.

Collaborators

Manythankstothefollowingcontributorsandreviewers:LucaBolognese,MikePizzo,KeithShort,MartinPetersen-Frey(PSS),PabloDeGrande,BernardChen(Sapient),DimitrisGeorgakopoulos(Sapient),KennyJones,ChrisBrooks,LanceHendrix,PradyumnaSiddhartha,FrancoA.Ceruti(VBNext),DiegoGonzalez(Lagash),andChrisSchoon.
Thanks,also,tothecontentteam:ChrisSfanos,AngelaCrocker,AndyOlsen,andSharonSmith.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息