|
Seperation af forretningslag og databaselagHvis du har prøvet af lave et website i ASP som bare er lidt komplekst, har du sikkert også kæmpet lidt med at holde tingene overskueligt. Det ender ofte med at databasekald og forretningsregler bliver flettet ind i HTML-kode og danner en dejlig suppe af spagettikode, som til tider kan være lidt frustrerende at vedligeholde. Desuden ender man i værste fald med at kode de samme ting flere gange, fordi det er for besværligt at udrede det man skal bruge fra den eksisterende kode og gøre det genbrugeligt. En vej fremad derfra, kunne være at opsplitte sin kode i funktioner og så fordele disse i en flok includefiler og forsøge at holde styr på hvilke includefiler der skulle bruges hvornår... Jeg vil dog prøve at beskrive en anden vej, nemlig ved at benytte klasser (se evt. andre artikler her på sitet, som omhandler brugen af klasser i VBScript). Med klasser kan vi indkapsle logikken og opdele den i nogle fornuftigt sammenhængende klumper, f.eks. forretningslogik og databaseintegrationslogik. Forretningslogik er det der håndterer reglerne og sammenhængene mellem forskellige elementer i systemet og databaseintegrationslogikken håndterer transporten af forretningsdata/-tilstand mellem forretningslaget og databasen. Databaseintegrationslaget håndterer som nævnt logikken vedr. transport af data og indkapsler optimalt set alt viden om hvordan data skal lagres og transporteres mellem databasen og forretningslaget. Hvis man kan opnå total isolation af denne viden i databaseintegrationslaget, kan man "let" udskifte den databaseplatform man anvender til fordel for en anden platform. Dette kunne f.eks. opstå i forbindelse med en opskalering af et site, som er "vokset fra" den eksisterende databaseløsning og har behov for flere kræfter i det lag. Det kunne også være en ændring af måden data behandles og transporteres mellem database og forretningslaget der skulle ændres, f.eks. bedre caching, eller en spredning af database over flere databaseservere som skulle håndteres. Alt dette kan ske isoleret i databaselaget, hvis man kan holde en stringent grænseflade mellem forretningslaget (og alt over det lag) og databaselaget. Min strategi går ud på, at benytte formatet for forretningsobjekter fra artiklen "forreningslag og validering" og så bygge et databaseintegrationslag på (som det også blev indikeret i nævnte artikel), der varetager datatransport. En databaseintegrationsklasse følger typisk en bestemt forretningsklasse, så derfor kan man godt inkludere filen med databaseintegrationsklassen i filen med forretningsklassen. På den måde skal man som bruger af forretningsklassen kun bekymre sig om at inkludere filen med forretningsklassen og endnu en "bekymring" er fjernet fra abonnentens mængde af "bekymringer" i forbindelse med konstruktionen af et komplekst system. Det essentielle af forretningsklassen i forbindelse med kommunikationen med databaseintegrationslaget:
class CPerson Som det ses oprettes der et nyt objekt som tager sig af den faktiske gem-operation. Det tager selve forretningsobjektet som parameter og bruger forretningsobjektet til at aflæse og sætte værdier i forbindelse med transporten af data. Det kunne f.eks. se således ud: class CPersonDOpublic sub Gem(fo) dim sql, conn, cmd, rs if fo.Id = 0 then sql = "INSERT INTO person(brugernavn,kodeord,email) VALUES(?,?,?)" else sql = "UPDATE person SET brugernavn = ?, kodeord = ?, email = ? WHERE id = ?" end if set conn = getConn() set cmd = Server.CreateObject("ADODB.Command") set cmd.ActiveConnection = conn cmd.CommandText = sql cmd.CommandType = adCmdText cmd.Parameters.Append _ cmd.CreateParameter("@brugernavn", adVarChar, _ adParamInput, 20, fo.Brugernavn) cmd.Parameters.Append _ cmd.CreateParameter("@kodeord", adVarChar, _ adParamInput, 20, fo.Kodeord) cmd.Parameters.Append _ cmd.CreateParameter("@email", adVarChar, _ adParamInput, 255, fo.Email) if fo.Id <> 0 then cmd.Parameters.Append _ cmd.CreateParameter("@id", adInteger, _ adParamInput, , fo.Id) end if cmd.Execute if fo.Id = 0 then ' Da det er et nyt objekt, så skal det nye Id hentes fra ' databasen og indsættes i forretningsobjektet, så det kan ' bruges videre og gemmes (dvs. opdateres) igen senere set cmd = Server.CreateObject("ADODB.Command") set cmd.ActiveConnection = conn cmd.CommandText = "SELECT @@IDENTITY" cmd.CommandType = adCmdText set rs = cmd.Execute() fo.Id = CLng(rs(0)) rs.Close set rs = nothing end if call conn.close() end sub end class Der er i ovenstående et par forudsætninger som skal være på plads. Dels skal ado-konstanterne være tilgængelige (enten via metatag i f.eks. global.asa eller via en includefil med konstanterne - den første anbefales!), dels skal der være en global funktion som kan hente et gyldigt connectionobjekt via funktionen getConn. Selve funktionen CPersonDO.Gem sørger for at tage stilling til om forretningsobjektet skal oprettes eller opdateres, hvilket besluttes på grundlag af forretningsobjektets aktuelle id og en antagelse af om id'et er 0 eller noget andet. Hvis det er nul, så findes det ikke i databasen (da databaseid'er typisk har en værdi større end 0, hvis de er autogenererede). Der kan naturligvis sagtens ligge andre regler til grund for identicerende kolonner i en database (og der bør i virkeligheden nok gøre det), men jeg har taget udgangspunkt i denne simple forudsætning, da det er den metode jeg typisk benytter i mine databasearkitekturer... |
| Sidst opdateret: 05-09-2010 00:08:02 |
|
Tilmeld link |
Tilføj Link |
Tilføj Link |
@-begynder Erklæring om beskyttelse af personlige oplysninger |