Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
I den här självstudien börjar vi från början och skapar Data Access Layer (DAL), med hjälp av typerade datauppsättningar, för att få åtkomst till informationen i en databas.
Inledning
Som webbutvecklare handlar våra liv om att arbeta med data. Vi skapar databaser för att lagra data, kod för att hämta och ändra dem samt webbsidor för att samla in och sammanfatta dem. Det här är den första handledningen i en lång serie som utforskar tekniker för att implementera dessa vanliga mönster i ASP.NET 2.0. Vi börjar med att skapa en programvaruarkitektur som består av ett dataåtkomstlager (DAL) med hjälp av typade datauppsättningar, ett BLL (Business Logic Layer) som tillämpar anpassade affärsregler och ett presentationslager som består av ASP.NET sidor som delar en gemensam sidlayout. När det här grundarbetet för serverdelen har lagts till övergår vi till rapportering och visar hur du visar, sammanfattar, samlar in och validerar data från ett webbprogram. De här självstudierna är inriktade på att vara koncisa och ge stegvisa instruktioner med massor av skärmdumpar som vägleder dig genom processen visuellt. Varje självstudiekurs är tillgänglig i C#- och Visual Basic-versioner och innehåller en nedladdning av den fullständiga koden som används. (Den här första handledningen är ganska lång, men resten presenteras i mycket mer lättsmälta delar.)
För de här självstudierna använder vi en Microsoft SQL Server 2005 Express Edition-version av Northwind-databasen som finns i App_Data
katalogen. Förutom databasfilen App_Data
innehåller mappen även SQL-skripten för att skapa databasen, om du vill använda en annan databasversion. Om du använder en annan SQL Server-version av Northwind-databasen måste du uppdatera NORTHWNDConnectionString
inställningen i programmets Web.config
fil. Webbprogrammet skapades med Visual Studio 2005 Professional Edition som ett filsystembaserat webbplatsprojekt. Alla handledningar fungerar dock lika bra med den kostnadsfria versionen av Visual Studio 2005, Visual Web Developer.
I den här självstudien börjar vi från början och skapar Data Access Layer (DAL), följt av att skapa Business Logic Layer (BLL) i den andra självstudien och arbeta med sidlayout och navigering i den tredje. Handledningarna efter den tredje kommer att bygga vidare på den grund som lades i de tre första. Vi har mycket att ta upp i den här första självstudien, så starta Visual Studio och kom igång!
Steg 1: Skapa ett webbprojekt och ansluta till databasen
Innan vi kan skapa vårt dal-lager (Data Access Layer) måste vi först skapa en webbplats och konfigurera databasen. Börja med att skapa en ny filsystembaserad ASP.NET webbplats. Det gör du genom att gå till menyn Arkiv och välja Ny webbplats och visa dialogrutan Ny webbplats. Välj mallen ASP.NET webbplats, ange listrutan Plats till Filsystem, välj en mapp för att placera webbplatsen och ange språket till Visual Basic.
Bild 1: Skapa en ny fil System-Based webbplats (Klicka om du vill visa en bild i full storlek)
Då skapas en ny webbplats med en Default.aspx
ASP.NET sida, en App_Data
mapp och en Web.config
fil.
När webbplatsen har skapats är nästa steg att lägga till en referens till databasen i Visual Studio Server Explorer. Genom att lägga till en databas i ServerUtforskaren kan du lägga till tabeller, lagrade procedurer, vyer och så vidare från Visual Studio. Du kan också visa tabelldata eller skapa egna frågor antingen för hand eller grafiskt via Query Builder. När vi skapar Typed DataSets för DAL måste vi dessutom peka Visual Studio på den databas som de typerade datauppsättningarna ska konstrueras från. Vi kan ange den här anslutningsinformationen vid den tidpunkten, men Visual Studio fyller automatiskt i en listruta över de databaser som redan har registrerats i Server Explorer.
Stegen för att lägga till Northwind-databasen i Server Explorer beror på om du vill använda SQL Server 2005 Express Edition-databasen i App_Data
mappen eller om du har en Microsoft SQL Server 2000- eller 2005-databasserverkonfiguration som du vill använda i stället.
Använda en databas i mappenApp_Data
Om du inte har en SQL Server 2000- eller 2005-databasserver att ansluta till, eller om du helt enkelt vill undvika att behöva lägga till databasen till en databasserver, kan du använda SQL Server 2005 Express Edition-versionen av Northwind-databasen som finns i den nedladdade webbplatsens App_Data
mapp (NORTHWND.MDF
).
En databas som placeras i App_Data
mappen läggs automatiskt till i ServerUtforskaren. Förutsatt att du har SQL Server 2005 Express Edition installerat på datorn bör du se en nod med namnet NORTHWND. MDF i Server Explorer, som du kan expandera och utforska dess tabeller, vyer, lagrade procedur och så vidare (se bild 2).
Mappen App_Data
kan också innehålla Microsoft Access-filer .mdb
, som, precis som deras SQL Server-motsvarigheter, automatiskt läggs till i Server Explorer. Om du inte vill använda något av SQL Server-alternativen kan du alltid installera Northwind Traders databas och appar och släppa dem i App_Data
katalogen. Tänk dock på att Access-databaser inte är lika funktionsrika som SQL Server och inte är utformade för att användas i webbplatsscenarier. Dessutom kommer ett par av de över 35 handledningarna att använda vissa funktioner på databasnivå som inte stöds av Access.
Ansluta till databasen i en Microsoft SQL Server 2000- eller 2005-databasserver
Du kan också ansluta till en Northwind-databas som är installerad på en databasserver. Om databasservern inte redan har Northwind-databasen installerad måste du först lägga till den i databasservern genom att köra installationsskriptet som ingår i nedladdningen av den här självstudien.
När du har installerat databasen går du till Serverutforskaren i Visual Studio, högerklickar på noden Dataanslutningar och väljer Lägg till anslutning. Om du inte ser serverutforskaren går du till View/Server Explorer eller trycker på Ctrl+Alt+S. Då visas dialogrutan Lägg till anslutning, där du kan ange vilken server du vill ansluta till, autentiseringsinformationen och databasnamnet. När du har konfigurerat informationen om databasanslutningen och klickat på KNAPPEN OK läggs databasen till som en nod under noden Dataanslutningar. Du kan expandera databasnoden för att utforska dess tabeller, vyer, lagrade procedurer och så vidare.
Bild 2: Lägg till en anslutning till databasserverns Northwind-databas
Steg 2: Skapa dataåtkomstskiktet
När du arbetar med data är ett alternativ att bädda in dataspecifik logik direkt i presentationslagret (i ett webbprogram utgör de ASP.NET sidorna presentationslagret). Detta kan ske i form av att skriva ADO.NET kod i ASP.NET-sidans koddel eller med hjälp av SqlDataSource-kontrollen från markeringsdelen. I båda fallen är den här metoden nära kopplad till dataåtkomstlogiken och presentationslagret. Den rekommenderade metoden är dock att separera dataåtkomstlogik från presentationslagret. Det här separata lagret kallas för Data Access Layer, DAL för kort och implementeras vanligtvis som ett separat klassbiblioteksprojekt. Fördelarna med den här skiktade arkitekturen är väldokumenterade (se avsnittet "Ytterligare läsningar" i slutet av den här självstudien för information om dessa fördelar) och är den metod vi kommer att använda i den här serien.
All kod som är specifik för den underliggande datakällan, till exempel att skapa en anslutning till databasen, utfärda SELECT
, INSERT
, UPDATE
och DELETE
kommandon och så vidare ska finnas i DAL. Presentationslagret bör inte innehålla några referenser till sådan dataåtkomstkod, utan i stället göra anrop till DAL för alla databegäranden. Dataåtkomstlager innehåller vanligtvis metoder för att komma åt underliggande databasdata. Northwind-databasen har till exempel tabellerna Products
och Categories
som registrerar produkterna till salu och de kategorier de tillhör. I vår DAL kommer vi att ha metoder som:
-
GetCategories(),
som returnerar information om alla kategorier -
GetProducts()
, som returnerar information om alla produkter -
GetProductsByCategoryID(categoryID)
, som returnerar alla produkter som tillhör en angiven kategori -
GetProductByProductID(productID)
, som returnerar information om en viss produkt
Dessa metoder, när de anropas, ansluter till databasen, utfärdar lämplig fråga och returnerar resultaten. Hur vi returnerar dessa resultat är viktigt. Dessa metoder kan enkelt returnera en DataSet eller DataReader som fylls i av databasfrågan, men helst bör dessa resultat returneras med hjälp av starkt typade objekt. Ett starkt typat objekt är ett vars schema är strikt definierat vid kompileringstillfället, medan motsatsen, ett löst typat objekt, är ett vars schema inte är känt förrän vid körning.
Till exempel är DataReader och DataSet (som standard) löst skrivna objekt eftersom deras schema definieras av de kolumner som returneras av databasfrågan som används för att fylla i dem. För att få åtkomst till en viss kolumn från en löst typad DataTable måste vi använda syntax som: DataTable.Rows(index)("columnName")
. DataTables lösa typning i det här exemplet visas av att vi måste komma åt kolumnnamnet genom en sträng eller ett ordningsindex. En starkt typad DataTable, å andra sidan, kommer att ha var och en av sina kolumner implementerade som egenskaper, vilket resulterar i kod som ser ut så här: DataTable.Rows(index).columnName
.
Utvecklare kan antingen skapa egna anpassade affärsobjekt eller använda Typed DataSets för att returnera starkt skrivna objekt. Ett affärsobjekt implementeras av utvecklaren som en klass vars egenskaper vanligtvis återspeglar kolumnerna i den underliggande databastabellen som affärsobjektet representerar. En Typed DataSet är en klass som genereras åt dig av Visual Studio baserat på ett databasschema och vars medlemmar är starkt skrivna enligt det här schemat. Själva Typed DataSet består av klasser som utökar klasserna ADO.NET DataSet, DataTable och DataRow. Förutom starkt skrivna DataTables inkluderar typade datauppsättningar nu även TableAdapters, som är klasser med metoder för att fylla i DataSet-datatabeller och sprida ändringar i DataTables tillbaka till databasen.
Anmärkning
Mer information om fördelarna och nackdelarna med att använda typade datauppsättningar jämfört med anpassade affärsobjekt finns i Designa komponenter på datanivå och Skicka data via nivåer.
Vi använder "starkt typade" DataSets för handledningarnas arkitektur. Bild 3 illustrerar arbetsflödet mellan de olika lagren i ett program som använder Typed DataSets.
Bild 3: All dataåtkomstkod flyttas till DAL (klicka om du vill visa en bild i full storlek)
Skapa en typinskriven datauppsättning och ett tabellkort
För att börja skapa vår DAL börjar vi med att lägga till en Typed DataSet i vårt projekt. Det gör du genom att högerklicka på projektnoden i Solution Explorer och välja Lägg till ett nytt objekt. Välj alternativet DataSet i listan med mallar och ge den Northwind.xsd
namnet .
Bild 4: Välj att lägga till en ny datauppsättning i projektet (klicka om du vill visa en bild i full storlek)
När du har klickat på Lägg till väljer du Ja när du uppmanas att lägga till DataSet i App_Code
mappen. Designern för den typerade datauppsättningen visas sedan och konfigurationsguiden TableAdapter startar, så att du kan lägga till din första TableAdapter i Typed DataSet.
En Typed DataSet fungerar som en starkt typad samling av data; den består av starkt typade DataTable-instanser, som i sin tur var och en består av starkt typade DataRow-instanser. Vi skapar en strikt typad DataTable för var och en av de underliggande databastabeller som vi behöver arbeta med i denna handledningsserie. Vi börjar med att skapa en DataTable för tabellen Products
.
Tänk på att starkt skrivna DataTables inte innehåller någon information om hur du kommer åt data från den underliggande databastabellen. För att hämta data för att fylla i DataTable använder vi en TableAdapter-klass som fungerar som vårt dataåtkomstlager. För vår Products
DataTable innehåller TableAdapter metoderna GetProducts()
, GetProductByCategoryID(categoryID)
och så vidare som vi anropar från presentationslagret. DataTables roll är att fungera som de starkt typade objekt som används för att överföra data mellan skikten.
Konfigurationsguiden för TableAdapter börjar med att uppmana dig att välja vilken databas du vill arbeta med. Listrutan visar dessa databaser i Serverutforskaren. Om du inte har lagt till Northwind-databasen i Serverutforskaren kan du klicka på knappen Ny anslutning för tillfället för att göra det.
Bild 5: Välj Northwind-databasen i Drop-Down-listan (Klicka om du vill visa en bild i full storlek)
När du har valt databasen och klickat på Nästa får du frågan om du vill spara anslutningssträngen Web.config
i filen. Genom att spara anslutningssträngen undviker du att hårdkoda den i TableAdapter-klasserna, vilket förenklar saker om informationen om anslutningssträngen ändras i framtiden. Om du väljer att spara anslutningssträngen i konfigurationsfilen placeras den i <connectionStrings>
avsnittet, som kan krypteras för bättre säkerhet eller ändras senare via den nya egenskapssidan ASP.NET 2.0 i IIS GUI Admin Tool, vilket är mer idealiskt för administratörer.
Bild 6: Spara anslutningssträngen till Web.config
(Klicka om du vill visa en bild i full storlek)
Därefter måste vi definiera schemat för den första starkt typade dataTabellen och ange den första metoden som TableAdapter ska använda när man fyller i det starkt typade DataSet. Dessa två steg utförs samtidigt genom att skapa en fråga som returnerar kolumnerna från tabellen som vi vill ska återspeglas i vår DataTable. I slutet av guiden ger vi denna sökfråga ett metodnamn. När det har utförts kan den här metoden anropas från presentationsskiktet. Metoden kör den definierade frågan och fyller i en starkt typad DataTable.
För att komma igång med att definiera SQL-frågan måste vi först ange hur vi vill att TableAdapter ska utfärda frågan. Vi kan använda en ad hoc SQL-instruktion, skapa en ny lagrad procedur eller använda en befintlig lagrad procedur. För de här handledningarna använder vi ad hoc SQL-instruktioner.
Bild 7: Fråga efter data med hjälp av en ad hoc SQL-instruktion (Klicka om du vill visa en bild i full storlek)
Nu kan vi skriva in SQL-frågan för hand. När du skapar den första metoden i TableAdapter vill du vanligtvis att frågan ska returnera de kolumner som måste uttryckas i motsvarande DataTable. Vi kan göra detta genom att skapa en fråga som returnerar alla kolumner och alla rader från Products
tabellen:
Bild 8: Ange SQL-frågan i textrutan (Klicka om du vill visa en bild i full storlek)
Du kan också använda Query Builder och grafiskt konstruera frågan, enligt bild 9.
Bild 9: Skapa frågan grafiskt via frågeredigeraren (Klicka om du vill visa en bild i full storlek)
När du har skapat frågan, men innan du går vidare till nästa skärm klickar du på knappen Avancerade alternativ. I Webbplatsprojekt är "Generera infognings-, uppdaterings- och borttagningsinstruktioner" det enda avancerade alternativet som valts som standard. Om du kör den här guiden från ett klassbibliotek eller ett Windows-projekt väljs även alternativet "Använd optimistisk samtidighet". Låt alternativet "Använd optimistisk samtidighet" vara avmarkerat för tillfället. Vi kommer att undersöka optimistisk samtidighet i framtida handledningar.
Bild 10: Välj endast instruktionsalternativet Generera infoga, uppdatera och ta bort (Klicka om du vill visa en bild i full storlek)
När du har verifierat de avancerade alternativen klickar du på Nästa för att gå vidare till den sista skärmen. Här uppmanas vi att välja vilka metoder som ska läggas till i TableAdapter. Det finns två mönster för att fylla i data:
-
Fyll en DataTable med denna metod skapas en metod som tar in en DataTable som en parameter och fyller den baserat på resultaten av frågan. Klassen ADO.NET DataAdapter implementerar till exempel det här mönstret med sin
Fill()
metod. - Returnera en DataTable med den här metoden som metoden skapar och fyller datatabellen åt dig och returnerar den som metodernas returvärde.
Du kan låta TableAdapter implementera ett eller båda av dessa mönster. Du kan också byta namn på de metoder som anges här. Låt oss låta båda kryssrutorna vara markerade, även om vi bara använder det senare mönstret i de här självstudierna. Vi byter också namn på den ganska generiska GetData
metoden till GetProducts
.
Om markerad, skapar den sista kryssrutan "GenerateDBDirectMethods" metoder Insert()
, Update()
och Delete()
för TableAdapter. Om du lämnar det här alternativet avmarkerat måste alla uppdateringar göras via TableAdapters enda Update()
metod, som tar in Typed DataSet, en DataTable, en enda DataRow eller en matris med DataRows. (Om du har avmarkerat instruktionen "Generera infoga, uppdatera och ta bort" från de avancerade egenskaperna i bild 9 kommer den här kryssrutans inställning inte att ha någon effekt.) Låt den här kryssrutan vara markerad.
Bild 11: Ändra metodnamnet från GetData
till GetProducts
(Klicka om du vill visa en bild i full storlek)
Slutför guiden genom att klicka på Avsluta. När guiden har stängts returneras vi till DataSet Designer som visar datatabellen som vi nyss skapade. Du kan se listan med kolumner i Products
DataTable (ProductID
, ProductName
och så vidare) samt metoderna för ProductsTableAdapter
(Fill()
och GetProducts()
).
Bild 12: DataTabellen Products
och ProductsTableAdapter
har lagts till i den inskrivna datamängden (Klicka om du vill visa en bild i full storlek)
Nu har vi en Typed DataSet med en enda DataTable (Northwind.Products
) och en starkt typad DataAdapter-klass (NorthwindTableAdapters.ProductsTableAdapter
) med en GetProducts()
metod. Dessa objekt kan användas för att komma åt en lista över alla produkter från kod som:
Dim productsAdapter As New NorthwindTableAdapters.ProductsTableAdapter()
Dim products as Northwind.ProductsDataTable
products = productsAdapter.GetProducts()
For Each productRow As Northwind.ProductsRow In products
Response.Write("Product: " & productRow.ProductName & "<br />")
Next
Den här koden krävde inte att vi skulle skriva en bit dataåtkomstspecifik kod. Vi behövde inte instansiera några ADO.NET klasser, vi behövde inte referera till några anslutningssträngar, SQL-frågor eller lagrade procedurer. TableAdapter tillhandahåller i stället dataåtkomstkoden på låg nivå åt oss.
Varje objekt som används i det här exemplet är också starkt typat, vilket gör att Visual Studio kan tillhandahålla IntelliSense och typkontroll vid kompilering. Och bäst av allt datatabeller som returneras av TableAdapter kan bindas till ASP.NET datawebbkontroller, till exempel GridView, DetailsView, DropDownList, CheckBoxList och flera andra. I följande exempel visas bindning av DataTable som returneras av GetProducts()
metoden till ett GridView på bara tre knappa rader med kod i Page_Load
händelsehanteraren.
AllProducts.aspx
<%@ Page Language="VB" AutoEventWireup="true" CodeFile="AllProducts.aspx.vb"
Inherits="AllProducts" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>View All Products in a GridView</title>
<link href="Styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
<form id="form1" runat="server">
<div>
<h1>
All Products</h1>
<p>
<asp:GridView ID="GridView1" runat="server"
CssClass="DataWebControlStyle">
<HeaderStyle CssClass="HeaderStyle" />
<AlternatingRowStyle CssClass="AlternatingRowStyle" />
</asp:GridView>
</p>
</div>
</form>
</body>
</html>
AllProducts.aspx.vb
Imports NorthwindTableAdapters
Partial Class AllProducts
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles Me.Load
Dim productsAdapter As New ProductsTableAdapter
GridView1.DataSource = productsAdapter.GetProducts()
GridView1.DataBind()
End Sub
End Class
Bild 13: Listan över produkter visas i en GridView (Klicka om du vill visa en bild i full storlek)
Det här exemplet krävde att vi skrev tre kodrader i händelsehanteraren för vår ASP.NET sida Page_Load
, men i framtida självstudier ska vi undersöka hur du använder ObjectDataSource för att deklarativt hämta data från DAL. Med ObjectDataSource kommer vi inte att behöva skriva någon kod och får även stöd för sidindelning och sortering!
Steg 3: Lägga till parametriserade metoder i dataåtkomstskiktet
I det här läget har klassen ProductsTableAdapter
bara en metod, GetProducts()
, som returnerar alla produkter i databasen. Det är definitivt användbart att kunna arbeta med alla produkter, men det finns tillfällen då vi vill hämta information om en specifik produkt eller alla produkter som tillhör en viss kategori. Om du vill lägga till sådana funktioner i vårt dataåtkomstlager kan vi lägga till parametriserade metoder i TableAdapter.
Nu ska vi lägga till GetProductsByCategoryID(categoryID)
metoden. Om du vill lägga till en ny metod i DAL går du tillbaka till DataSet Designer, högerklickar i ProductsTableAdapter
avsnittet och väljer Lägg till fråga.
Bild 14: Right-Click på TableAdapter och Välj Lägg till fråga
Vi tillfrågas först om vi vill komma åt databasen med hjälp av en ad hoc SQL-instruktion eller en ny eller befintlig lagrad procedur. Nu väljer vi att använda en ad hoc SQL-instruktion igen. Därefter tillfrågas vi om vilken typ av SQL-fråga vi vill använda. Eftersom vi vill returnera alla produkter som tillhör en angiven kategori vill vi skriva en SELECT
instruktion som returnerar rader.
Bild 15: Välj att skapa en SELECT
instruktion som returnerar rader (klicka om du vill visa en bild i full storlek)
Nästa steg är att definiera DEN SQL-fråga som används för att komma åt data. Eftersom vi bara vill returnera de produkter som tillhör en viss kategori använder jag samma SELECT
instruktion från GetProducts()
, men lägger till följande WHERE
sats: WHERE CategoryID = @CategoryID
. Parametern @CategoryID
anger för guiden TableAdapter att metoden vi skapar kräver en indataparameter av motsvarande typ (dvs. ett heltal som kan vara null).
Bild 16: Ange en fråga för att endast returnera produkter i en angiven kategori (Klicka om du vill visa en bild i full storlek)
I det sista steget kan vi välja vilka dataåtkomstmönster som ska användas, samt anpassa namnen på de metoder som genereras. För fyllningsmönstret ska vi ändra namnet till FillByCategoryID
och för returen ett DataTable-returmönster ( GetX
metoderna) ska vi använda GetProductsByCategoryID
.
Bild 17: Välj namnen för TableAdapter-metoderna (Klicka om du vill visa en bild i full storlek)
När du har slutfört guiden innehåller DataSet Designer de nya TableAdapter-metoderna.
Bild 18: Produkterna kan nu efterfrågas efter kategori
Ta en stund att lägga till en GetProductByProductID(productID)
metod med samma teknik.
Dessa parametriserade frågor kan testas direkt från DataSet Designer. Högerklicka på metoden i TableAdapter och välj Förhandsgranska data. Ange sedan de värden som ska användas för parametrarna och klicka på Förhandsgranska.
Bild 19: De produkter som hör till kategorin Drycker visas (Klicka om du vill visa en bild i full storlek)
GetProductsByCategoryID(categoryID)
Med metoden i vår DAL kan vi nu skapa en ASP.NET sida som endast visar dessa produkter i en angiven kategori. I följande exempel visas alla produkter som finns i kategorin Drycker, som har värdet CategoryID
1.
Beverages.aspx
<%@ Page Language="VB" AutoEventWireup="true" CodeFile="Beverages.aspx.vb"
Inherits="Beverages" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
<link href="Styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
<form id="form1" runat="server">
<div>
<h1>Beverages</h1>
<p>
<asp:GridView ID="GridView1" runat="server"
CssClass="DataWebControlStyle">
<HeaderStyle CssClass="HeaderStyle" />
<AlternatingRowStyle CssClass="AlternatingRowStyle" />
</asp:GridView>
</p>
</div>
</form>
</body>
</html>
Beverages.aspx.vb
Imports NorthwindTableAdapters
Partial Class Beverages
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles Me.Load
Dim productsAdapter As New ProductsTableAdapter
GridView1.DataSource =
productsAdapter.GetProductsByCategoryID(1)
GridView1.DataBind()
End Sub
End Class
Bild 20: Dessa produkter i kategorin Drycker visas (Klicka om du vill visa en bild i full storlek)
Steg 4: Infoga, uppdatera och ta bort data
Det finns två mönster som ofta används för att infoga, uppdatera och ta bort data. Det första mönstret, som jag kallar databasens direktmönster, handlar om att skapa metoder som, när det anropas, utfärdar ett INSERT
, UPDATE
eller DELETE
-kommando till databasen som fungerar på en enda databaspost. Sådana metoder skickas vanligtvis i en serie skalära värden (heltal, strängar, booleska värden, DateTimes och så vidare) som motsvarar värdena för att infoga, uppdatera eller ta bort. Med det här mönstret för Products
tabellen skulle borttagningsmetoden till exempel ta in en heltalsparameter som anger ProductID
posten som ska tas bort, medan insert-metoden skulle ta in en sträng för ProductName
, en decimal för UnitPrice
, ett heltal för UnitsOnStock
och så vidare.
Bild 21: Varje infognings-, uppdaterings- och borttagningsbegäran skickas till databasen omedelbart (klicka om du vill visa en bild i full storlek)
Det andra mönstret, som jag kallar batchuppdateringsmönstret, är att uppdatera en hel DataSet, DataTable eller insamling av DataRows i ett metodanrop. Med det här mönstret tar en utvecklare bort, lägger till och ändrar DataRows i en DataTable och skickar sedan dessa DataRows eller DataTable till en uppdateringsmetod. Den här metoden räknar sedan upp datarows som skickas in, avgör om de har ändrats, lagts till eller tagits bort (via DataRows RowState-egenskapsvärde ) och utfärdar lämplig databasbegäran för varje post.
Bild 22: Alla ändringar synkroniseras med databasen när uppdateringsmetoden anropas (Klicka om du vill visa en bild i full storlek)
TableAdapter använder batchuppdateringsmönstret som standard, men stöder även db-direktmönstret. Eftersom vi valde alternativet "Generera infognings-, uppdaterings- och borttagningsuttryck" från avancerade egenskaper när vi skapade vår TableAdapter, ProductsTableAdapter
innehåller metoden en Update()
metod som implementerar batchuppdateringsmönstret. Mer specifikt innehåller TableAdapter en Update()
metod som kan skickas till Typed DataSet, en starkt typad DataTable eller en eller flera DataRows. Om du lämnade kryssrutan "GenerateDBDirectMethods" markerad när du först skapade TableAdapter implementeras db-direktmönstret också via Insert()
, Update()
och Delete()
-metoder.
Båda datamodifieringsmönstren använder TableAdapter-egenskaperna InsertCommand
, UpdateCommand
och DeleteCommand
för att utfärda kommandona INSERT
, UPDATE
och DELETE
till databasen. Du kan inspektera och ändra InsertCommand
egenskaperna , UpdateCommand
och DeleteCommand
genom att klicka på TableAdapter i DataSet Designer och sedan gå till fönstret Egenskaper. (Kontrollera att du har valt TableAdapter och att objektet är det objekt som ProductsTableAdapter
har valts i listrutan i fönstret Egenskaper.)
Bild 23: TableAdapter har InsertCommand
, UpdateCommand
och DeleteCommand
egenskaper (Klicka om du vill visa en bild i full storlek)
Om du vill undersöka eller ändra någon av dessa egenskaper för databaskommandon klickar du på CommandText
underegenskaperna, som tar upp Query Builder.
Bild 24: Konfigurera instruktionen INSERT
, UPDATE
och DELETE
i Query Builder (Klicka om du vill visa en bild i full storlek)
Följande kodexempel visar hur du använder batchuppdateringsmönstret för att fördubbla priset för alla produkter som inte har upphört och som har 25 enheter i lager eller mindre:
Dim productsAdapter As New NorthwindTableAdapters.ProductsTableAdapter()
Dim products As Northwind.ProductsDataTable = productsAdapter.GetProducts()
For Each product As Northwind.ProductsRow In products
If Not product.Discontinued AndAlso product.UnitsInStock <= 25 Then
product.UnitPrice *= 2
End if
Next
productsAdapter.Update(products)
Koden nedan visar hur du använder db-direktmönstret för att programmatiskt ta bort en viss produkt, sedan uppdatera en och sedan lägga till en ny:
Dim productsAdapter As New NorthwindTableAdapters.ProductsTableAdapter()
productsAdapter.Delete(3)
productsAdapter.Update( _
"Chai", 1, 1, "10 boxes x 20 bags", 18.0, 39, 15, 10, false, 1)
productsAdapter.Insert( _
"New Product", 1, 1, "12 tins per carton", 14.95, 15, 0, 10, false)
Skapa anpassade metoder för att infoga, uppdatera och ta bort
Metoderna Insert()
, Update()
och som Delete()
skapas av DB-direktmetoden kan vara lite besvärliga, särskilt för tabeller med många kolumner. Om du tittar på det tidigare kodexemplet, utan IntelliSenses hjälp, är det inte särskilt tydligt vilken tabellkolumn som Products
mappar till varje indataparameter till Update()
metoderna och Insert()
. Det kan finnas tillfällen då vi bara vill uppdatera en enskild kolumn eller två eller vill ha en anpassad Insert()
metod som kanske returnerar värdet för den nyligen infogade postens IDENTITY
fält (automatisk inkrement).
Om du vill skapa en sådan anpassad metod går du tillbaka till DataSet Designer. Högerklicka på TableAdapter och välj Lägg till fråga och gå tillbaka till guiden TableAdapter. På den andra skärmen kan vi ange vilken typ av fråga som ska skapas. Nu ska vi skapa en metod som lägger till en ny produkt och sedan returnerar värdet för den nyligen tillagda postens ProductID
. Välj därför att skapa en INSERT
fråga.
Bild 25: Skapa en metod för att lägga till en ny rad i Products
tabellen (Klicka om du vill visa en bild i full storlek)
På nästa skärm visas InsertCommand
s CommandText
. Utöka den här frågan genom att lägga till SELECT SCOPE_IDENTITY()
i slutet av frågan, vilket returnerar det sista identitetsvärdet som infogats i en IDENTITY
kolumn i samma omfång. (Se den tekniska dokumentationen för mer information om SCOPE_IDENTITY()
och varför du förmodligen vill använda SCOPE_IDENTITY() i stället för @@IDENTITY.) Se till att du avslutar -instruktionen INSERT
med ett semikolon innan du lägger till -instruktionen SELECT
.
Bild 26: Utöka frågan för att returnera SCOPE_IDENTITY()
värdet (Klicka om du vill visa en bild i full storlek)
Namnge slutligen den nya metoden InsertProduct
.
Bild 27: Ange nytt metodnamn till InsertProduct
(Klicka om du vill visa en bild i full storlek)
När du återvänder till DataSet Designer ser du att ProductsTableAdapter
innehåller en ny metod, InsertProduct
. Om den här nya metoden inte har någon parameter för varje kolumn i Products
tabellen är chansen stor att du har glömt att avsluta -instruktionen INSERT
med ett semikolon.
InsertProduct
Konfigurera metoden och se till att du har ett semikolon som avgränsar - och-uttrycken INSERT
SELECT
.
Som standard utfärdar infogningsmetoder icke-frågemetoder, vilket innebär att de returnerar antalet berörda rader. Vi vill InsertProduct
dock att metoden ska returnera det värde som returneras av frågan, inte antalet rader som påverkas. För att åstadkomma detta, justera metodens InsertProduct
egenskap till ExecuteMode
.
Bild 28: Ändra egenskapen ExecuteMode
till Scalar
(Klicka om du vill visa en bild i full storlek)
Följande kod visar den här nya InsertProduct
metoden i praktiken:
Dim productsAdapter As New NorthwindTableAdapters.ProductsTableAdapter()
Dim new_productID As Integer = Convert.ToInt32(productsAdapter.InsertProduct( _
"New Product", 1, 1, "12 tins per carton", 14.95, 10, 0, 10, false))
productsAdapter.Delete(new_productID)
Steg 5: Slutföra dataåtkomstlagret
Observera att ProductsTableAdapters
klassen returnerar CategoryID
värdena och SupplierID
från Products
tabellen, men inte innehåller CategoryName
kolumnen från Categories
tabellen eller CompanyName
kolumnen från Suppliers
tabellen, även om dessa troligen är de kolumner som vi vill visa när produktinformationen visas. Vi kan utöka TableAdapters initiala metod GetProducts()
så att både CategoryName
- och CompanyName
-kolumnvärdena inkluderas, vilket uppdaterar den starkt typade DataTable så att även dessa nya kolumner inkluderas.
Detta kan dock innebära ett problem eftersom TableAdapter-metoderna för att infoga, uppdatera och ta bort data baseras på den här initiala metoden. Lyckligtvis påverkas inte de automatiskt genererade metoderna för infogning, uppdatering och borttagning av underfrågor i SELECT
-satsen. Genom att lägga till våra frågor i Categories
och Suppliers
som underfrågor, i stället JOIN
för s, undviker vi att behöva omarbeta dessa metoder för att ändra data. Högerklicka på GetProducts()
metoden i ProductsTableAdapter
och välj Konfigurera. Justera SELECT
sedan satsen så att den ser ut så här:
SELECT ProductID, ProductName, SupplierID, CategoryID,
QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued,
(SELECT CategoryName FROM Categories
WHERE Categories.CategoryID = Products.CategoryID) as CategoryName,
(SELECT CompanyName FROM Suppliers
WHERE Suppliers.SupplierID = Products.SupplierID) as SupplierName
FROM Products
Bild 29: Uppdatera instruktionen SELECT
GetProducts()
för metoden (Klicka om du vill visa en bild i full storlek)
När du har uppdaterat GetProducts()
metoden för att använda den här nya frågan innehåller DataTable två nya kolumner: CategoryName
och SupplierName
.
Bild 30: Products
DataTable har två nya kolumner
Ta en stund att uppdatera SELECT
satsen i GetProductsByCategoryID(categoryID)
-metoden också.
Om du använder syntaxen GetProducts()
för att uppdatera SELECT
JOIN
kommer inte DataSet Designer att kunna generera metoderna för att infoga, uppdatera och ta bort databasdata automatiskt med hjälp av DB-direktmönstret. I stället måste du skapa dem manuellt på samma sätt som vi gjorde med InsertProduct
-metoden tidigare i den här självstudien. Dessutom måste du manuellt ange egenskapsvärdena InsertCommand
, UpdateCommand
och DeleteCommand
om du vill använda batchuppdateringsmönstret.
Lägga till återstående TableAdapters
Hittills har vi bara tittat på att arbeta med en enda TableAdapter för en enskild databastabell. Northwind-databasen innehåller dock flera relaterade tabeller som vi behöver arbeta med i vårt webbprogram. En Typed DataSet kan innehålla flera relaterade DataTables. För att slutföra vår DAL behöver vi därför lägga till DataTables för de andra tabellerna som vi kommer att använda i de här självstudierna. Om du vill lägga till en ny TableAdapter i en Typed DataSet öppnar du DataSet Designer, högerklickar i Designer och väljer Lägg till/TableAdapter. Detta skapar en ny DataTable och TableAdapter och vägleder dig genom guiden som vi granskade tidigare i den här handledningen.
Det tar några minuter att skapa följande TableAdapters och metoder med hjälp av följande frågor. Observera att frågorna i ProductsTableAdapter
inkluderar underfrågorna för att hämta varje produkts kategori- och leverantörsnamn. Om du har följt med har du dessutom redan lagt till ProductsTableAdapter
klassens GetProducts()
och GetProductsByCategoryID(categoryID)
metoderna.
ProductsTableAdapter
GetProducts:
SELECT ProductID, ProductName, SupplierID, CategoryID, QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued, (SELECT CategoryName FROM Categories WHERE Categories.CategoryID = Products.CategoryID) as CategoryName, (SELECT CompanyName FROM Suppliers WHERE Suppliers.SupplierID = Products.SupplierID) as SupplierName FROM Products
GetProductsByCategoryID:
SELECT ProductID, ProductName, SupplierID, CategoryID, QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued, (SELECT CategoryName FROM Categories WHERE Categories.CategoryID = Products.CategoryID) as CategoryName, (SELECT CompanyName FROM Suppliers WHERE Suppliers.SupplierID = Products.SupplierID) as SupplierName FROM Products WHERE CategoryID = @CategoryID
GetProductsBySupplierID:
SELECT ProductID, ProductName, SupplierID, CategoryID, QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued, (SELECT CategoryName FROM Categories WHERE Categories.CategoryID = Products.CategoryID) as CategoryName, (SELECT CompanyName FROM Suppliers WHERE Suppliers.SupplierID = Products.SupplierID) as SupplierName FROM Products WHERE SupplierID = @SupplierID
GetProductByProductID:
SELECT ProductID, ProductName, SupplierID, CategoryID, QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued, (SELECT CategoryName FROM Categories WHERE Categories.CategoryID = Products.CategoryID) as CategoryName, (SELECT CompanyName FROM Suppliers WHERE Suppliers.SupplierID = Products.SupplierID) as SupplierName FROM Products WHERE ProductID = @ProductID
KategorierTabelladapter
GetCategories:
SELECT CategoryID, CategoryName, Description FROM Categories
GetCategoryByCategoryID:
SELECT CategoryID, CategoryName, Description FROM Categories WHERE CategoryID = @CategoryID
Leverantörstabelladaptör
GetSuppliers:
SELECT SupplierID, CompanyName, Address, City, Country, Phone FROM Suppliers
GetSuppliersByCountry:
SELECT SupplierID, CompanyName, Address, City, Country, Phone FROM Suppliers WHERE Country = @Country
GetSupplierBySupplierID:
SELECT SupplierID, CompanyName, Address, City, Country, Phone FROM Suppliers WHERE SupplierID = @SupplierID
EmployeesTableAdapter (på engelska)
GetEmployees:
SELECT EmployeeID, LastName, FirstName, Title, HireDate, ReportsTo, Country FROM Employees
GetEmployeesByManager:
SELECT EmployeeID, LastName, FirstName, Title, HireDate, ReportsTo, Country FROM Employees WHERE ReportsTo = @ManagerID
GetEmployeeByEmployeeID:
SELECT EmployeeID, LastName, FirstName, Title, HireDate, ReportsTo, Country FROM Employees WHERE EmployeeID = @EmployeeID
Bild 31: Datauppsättningsdesignern efter att de fyra TableAdapters har lagts till (klicka om du vill visa en bild i full storlek)
Lägga till anpassad kod i DAL
TableAdapters och DataTables som lagts till i Typed DataSet uttrycks som en XML-schemadefinitionsfil (Northwind.xsd
). Du kan visa den här schemainformationen Northwind.xsd
genom att högerklicka på filen i Solution Explorer och välja Visa kod.
Bild 32: XML-schemadefinitionsfilen (XSD) för DataSeten Northwinds-typ (klicka om du vill visa en bild i full storlek)
Den här schemainformationen översätts till C# eller Visual Basic-kod vid designtillfället när den kompileras eller vid körning (om det behövs), då du kan gå igenom den med felsökningsprogrammet. Om du vill visa den här automatiskt genererade koden går du till klassvyn och ökar detaljnivån till klasserna TableAdapter eller Typed DataSet. Om du inte ser klassvyn på skärmen går du till menyn Visa och väljer den därifrån eller trycker på Ctrl+Skift+C. I klassvyn kan du se egenskaperna, metoderna och händelserna för klasserna Typed DataSet och TableAdapter. Om du vill visa koden för en viss metod dubbelklickar du på metodnamnet i klassvyn eller högerklickar på den och väljer Gå till definition.
Bild 33: Inspektera den automatiskt genererade koden genom att välja Gå till definition från klassvyn
Även om automatisk genererad kod kan vara en bra tidssparare är koden ofta mycket allmän och måste anpassas för att uppfylla de unika behoven i ett program. Risken med att utöka automatiskt genererad kod är dock att verktyget som genererade koden kan avgöra att det är dags att "återskapa" och skriva över dina anpassningar. Med .NET 2.0:s nya partiella klasskoncept är det enkelt att dela upp en klass i flera filer. På så sätt kan vi lägga till egna metoder, egenskaper och händelser i de automatiskt genererade klasserna utan att behöva oroa oss för att Visual Studio ska skriva över våra anpassningar.
Vi visar hur du anpassar DAL genom att lägga till en GetProducts()
metod i SuppliersRow
klassen. Klassen SuppliersRow
representerar en enda post i Suppliers
tabellen. Varje leverantör kan tillhandahålla noll till många produkter, så GetProducts()
returnerar de produkterna från den angivna leverantören. För att åstadkomma detta skapar du en ny klassfil i App_Code
mappen med namnet SuppliersRow.vb
och lägger till följande kod:
Imports NorthwindTableAdapters
Partial Public Class Northwind
Partial Public Class SuppliersRow
Public Function GetProducts() As Northwind.ProductsDataTable
Dim productsAdapter As New ProductsTableAdapter
Return productsAdapter.GetProductsBySupplierID(Me.SupplierID)
End Function
End Class
End Class
Den här partiella klassen instruerar kompilatorn att när du skapar Northwind.SuppliersRow
klassen så att den innehåller den GetProducts()
metod som vi precis har definierat. Om du skapar projektet och sedan återgår till klassvyn visas GetProducts()
nu som en metod för Northwind.SuppliersRow
.
Bild 34: Metoden GetProducts()
är nu en del av Northwind.SuppliersRow
klassen
Metoden GetProducts()
kan nu användas för att räkna upp produktuppsättningen för en viss leverantör, som följande kod visar:
Dim suppliersAdapter As New NorthwindTableAdapters.SuppliersTableAdapter()
Dim suppliers As Northwind.SuppliersDataTable = suppliersAdapter.GetSuppliers()
For Each supplier As Northwind.SuppliersRow In suppliers
Response.Write("Supplier: " & supplier.CompanyName)
Response.Write("<ul>")
Dim products As Northwind.ProductsDataTable = supplier.GetProducts()
For Each product As Northwind.ProductsRow In products
Response.Write("<li>" & product.ProductName & "</li>")
Next
Response.Write("</ul><p> </p>")
Next
Denna data kan också visas i någon av ASP.NET:s datawebbkontroller. På följande sida används en GridView-kontroll med två fält:
- Ett BoundField som visar namnet på varje leverantör och
- Ett TemplateField som innehåller en bulletedList-kontroll som är bunden till de resultat som returneras av
GetProducts()
metoden för varje leverantör.
Vi kommer att undersöka hur man visar sådana master-detaljrapporter i framtida självstudier. För tillfället är det här exemplet utformat för att illustrera med hjälp av den anpassade metod som lagts till i Northwind.SuppliersRow
klassen.
LeverantörerOchProdukter.aspx
<%@ Page Language="VB" CodeFile="SuppliersAndProducts.aspx.vb"
AutoEventWireup="true" Inherits="SuppliersAndProducts" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
<link href="Styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
<form id="form1" runat="server">
<div>
<h1>
Suppliers and Their Products</h1>
<p>
<asp:GridView ID="GridView1" runat="server"
AutoGenerateColumns="False"
CssClass="DataWebControlStyle">
<HeaderStyle CssClass="HeaderStyle" />
<AlternatingRowStyle CssClass="AlternatingRowStyle" />
<Columns>
<asp:BoundField DataField="CompanyName"
HeaderText="Supplier" />
<asp:TemplateField HeaderText="Products">
<ItemTemplate>
<asp:BulletedList ID="BulletedList1"
runat="server" DataSource="<%# CType(CType(Container.DataItem, System.Data.DataRowView).Row, Northwind.SuppliersRow).GetProducts() %>"
DataTextField="ProductName">
</asp:BulletedList>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</p>
</div>
</form>
</body>
</html>
SuppliersAndProducts.aspx.vb
Imports NorthwindTableAdapters
Partial Class SuppliersAndProducts
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles Me.Load
Dim suppliersAdapter As New SuppliersTableAdapter
GridView1.DataSource = suppliersAdapter.GetSuppliers()
GridView1.DataBind()
End Sub
End Class
Bild 35: Leverantörens företagsnamn visas i den vänstra kolumnen, deras produkter till höger (klicka om du vill visa en bild i full storlek)
Sammanfattning
När du bygger en webbapplikation bör skapandet av DAL vara ett av dina första steg, innan du börjar skapa presentationslagret. Med Visual Studio är det en uppgift som kan utföras på 10–15 minuter att skapa en DAL baserat på typbaserade datauppsättningar utan att behöva skriva en kodrad. Handledningarna i fortsättningen bygger på denna DAL. I nästa handledning ska vi definiera ett antal affärsregler och se hur vi implementerar dem i ett separat affärslogikskikt.
Lycka till med programmerandet!
Ytterligare läsning
Mer information om de ämnen som beskrivs i den här självstudien finns i följande resurser:
- Skapa en DAL med hjälp av starkt typerade TableAdapters och DataTables i VS 2005 och ASP.NET 2.0
- Utforma datanivåkomponenter och skicka data via nivåer
- Kryptera konfigurationsinformation i ASP.NET 2.0-program
- Översikt över TableAdapter
- Arbeta med en typad datauppsättning
- Använda Strongly-Typed Data Access i Visual Studio 2005 och ASP.NET 2.0
- Hur man utökar TableAdapter-metoder
Videoutbildning om ämnen som finns i den här handledningen
- Dataåtkomstlager i ASP.NET-program
- Så här manuellt binder du en datauppsättning till ett datagrid
- Arbeta med datauppsättningar och filter från ett ASP-program
Om författaren
Scott Mitchell, författare till sju ASP/ASP.NET-böcker och grundare av 4GuysFromRolla.com, har arbetat med Microsofts webbtekniker sedan 1998. Scott arbetar som oberoende konsult, tränare och författare. Hans senaste bok är Sams Teach Yourself ASP.NET 2.0 på 24 timmar. Han kan nås på mitchell@4GuysFromRolla.com.
Särskilt tack till
Den här självstudieserien granskades av många användbara granskare. Huvudgranskare för den här självstudien var Ron Green, Hilton Giesenow, Dennis Patterson, Liz Shulok, Abel Gomez och Carlos Santos. Vill du granska mina kommande MSDN-artiklar? Om så är fallet, hör av dig på mitchell@4GuysFromRolla.com.