Rainer's profileCyrons BlogPhotosBlogListsMore ![]() | Help |
|
|
November 30 Update in einem GridView mit foreign keys
Es ist ein Kinderspiel, mit dem Designer eine Gridview zu erstellen, das alle 4 SQL-Funktionen anbietet - solange es sich um eine ganz simple DB-Tabelle handelt. Einfach die Tabelle vom Server Explorer auf die Design-Oberfläche der aspx-Seite ziehen, noch editing und deleting anhaken und fertig ist die Laube. Ganz anders stellt es sich dar, wenn die GridView Daten darstellen soll, die aus verschiedenen Tabellen stammen und diese auch noch miteinander in Beziehung stehen.
Problem : Wandelt man im Dataset (xsd-File) die Basis-SELECT-Funktion so um, daß sie mittels INNER JOIN zu den in Beziehung stehenden Tabellen verbindet, werden die UPDATE-, INSERT- und Delete-Methoden nicht geschrieben. Lösung: Man schreibt die SELECT-Anweisung trotzdem mit INNER JOINS. Es müssen nur zusätzliche Funktionen für INSERT, UPDATE und DELETE geschrieben werden. Sinnvollerweise geschieht das in Form von Stored Procedures. Das entlastet den Webserver, weil ein Teil der Arbeit an den SQL-Server abgegeben wird.
Problem: Die Tabelle, die foreign keys enthält wird für die GridView benutzt. Diese Keys sollen aber 1. nicht angezeigt werden und 2. es ist dem User nicht zuzumuten, daß er GUIDs eintippt um andere Daten der verbundenen Tabellen zu referenzieren. Lösung: Die PK-Spalte kann ganz einfach über das Bool-Property "Visible" ausgeblendet werden. FK-Spalten gibt es nicht mehr, aber dazu weiter unten mehr. Das mit den GUIDs ist nur leicht komplizierter, wirklich kein großes Ding. Hier ist eine Update-Funktion in Form einer Stored Procedure:
ALTER PROCEDURE dbo.UpdatePC ( @PC_ID uniqueidentifier, @Bezeichnung varchar(50), @Inventarnummer varchar(50), @Kostentraeger varchar(50), @Seriennummer varchar(50), @Zustand varchar(50), @Sonderregelung varchar(255), @LieferantName varchar(50), @Herstellername varchar(50) )
AS SET NOCOUNT OFF DECLARE @ID_Hersteller uniqueidentifier DECLARE @ID_Lieferant uniqueidentifier DECLARE @ID_Zustand uniqueidentifier -- Zugehörige IDs holen SET @ID_Hersteller = (SELECT Hersteller_ID FROM T_Hersteller WHERE (Herstellername = @Herstellername)) SET @ID_Lieferant = (SELECT Lieferant_ID FROM T_Lieferant WHERE (LieferantName = @LieferantName)) SET @ID_Zustand = (SELECT Zustand_ID FROM T_Zustand WHERE (Zustand = @Zustand)) -- Update UPDATE T_PC SET [Bezeichnung] = @Bezeichnung, [Inventarnummer] = @Inventarnummer, [Kostentraeger] = @Kostentraeger, [Seriennummer] = @Seriennummer, [ID_Zustand] = @ID_Zustand, [Sonderregelung] = @Sonderregelung, [ID_Lieferant] = @ID_Lieferant, [ID_Hersteller] = @ID_Hersteller WHERE (PC_ID = @PC_ID) RETURN
Im Dataset wird der SELECT so umgebaut, daß die FK-Columns nicht mehr ausgewählt werden. Dafür werden die Felder der gebundenen Tabellen ausgewählt, die statt dessen angezeigt werden sollen. Hier die SELECT-Anweisung: SELECT T_PC.PC_ID, T_PC.Bezeichnung, T_PC.Inventarnummer, T_PC.Kostentraeger, T_PC.Seriennummer, T_PC.Sonderregelung, T_Hersteller.Herstellername, T_Lieferant.LieferantName, T_Zustand.Zustand FROM T_PC INNER JOIN T_Zustand ON T_PC.ID_Zustand = T_Zustand.Zustand_ID INNER JOIN T_Lieferant ON T_PC.ID_Lieferant = T_Lieferant.Lieferant_ID INNER JOIN T_Hersteller ON T_PC.ID_Hersteller = T_Hersteller.Hersteller_ID
Zurück zur UPDATE-Funktion. Man sieht dort, daß die Werte der verbundenen Tabellen referenziert werden und damit die passende ID geholt wird, um sie in das FK-Feld der Haupt-Tabelle einzusetzen. Beispiel: SET @ID_Zustand = (SELECT Zustand_ID FROM T_Zustand WHERE (Zustand = @Zustand))
Problem: Wie gibt man für die GridView verschiedene Funktionen an? Lösung: In der SQL-DataSource wird mit "Configure DataSource" "Specify a custom SQL-Statement or stored procedure" ausgewählt. Damit bekommt man für alle 4 SQL-Funktionen separate Möglichkeiten.
Problem: SQLVariant kann nicht in uniqueidentifier umgewandelt werden So oder so ähnlich lautete die Exception. Alle Parameter des Typs GUID werden durch den Datasource-Designer als Typ Objekt behandelt. Hier handelt es sich um einen Bug in Visual Studio. Lösung: Den Typ-Spezifizierer im aspx-Code löschen. Beispiel: <InsertParameters> <asp:Parameter Name="PC_ID" /> <asp:Parameter Name="Bezeichnung" Type="String" /> <asp:Parameter Name="Inventarnummer" Type="String" /> <asp:Parameter Name="Kostentraeger" Type="String" /> <asp:Parameter Name="Seriennummer" Type="String" /> <asp:Parameter Name="ID_Zustand" /> <asp:Parameter Name="Sonderregelung" Type="String" /> <asp:Parameter Name="ID_Lieferant" /> <asp:Parameter Name="ID_Hersteller" /> </InsertParameters>
Hier kann man sehen daß alle ID-Parameter keinen Typ mehr haben.
Problem: Procedure or function has too many arguments specified Diese Exception hat mich auch wieder ein paar graue Haare gekostet. Lösung: Alle Parameternamen müssen exakt den Feldnamen der Tabellen entsprechen! Die Trace-Funktion kann beim Aufspüren des Täters wertvolle Hilfe leisten. Um die Trace-Funktion zu aktivieren, schreibt man in die Headerzeile der aspx-Seite das Attribut Trace="true". Beispiel: <%@ Page Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true" CodeFile="PC.aspx.cs" Inherits="PC" Title="PC-Form" ErrorPage="~/GenericErrorPage.htm" Trace="true"%>
Das reicht aber noch nicht. Damit die gewünschten Werte auch angezeigt werden, bedarf es einer Methode: /// <summary> /// Dieser Eventhandler liefert im Tracemodus alle Parameter, die an die Stored Procedure UpdatePC übergeben werden. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void SqlDataSource_PC_Updating(object sender, SqlDataSourceCommandEventArgs e) { string TraceValue = string.Empty; object test = null; for(int i = 0; i < e.Command.Parameters.Count; i++) { Trace.Write(e.Command.Parameters[i].ParameterName); test = e.Command.Parameters[i].Value; if(test != null) { TraceValue = test.ToString(); Trace.Write(TraceValue); } } }
Problem: Der Primary Key der Haupttabelle wird bei einem UPDATE nicht übergeben. Lösung: Zuerst muß sichergestellt werden, daß der PK-Parameter überhaupt vom Designer generiert wird. Bei Bedarf muß er von Hand hinzugefügt werden. Dann braucht dieser Parameter folgende Attribute: Achso, erst einmal möchte ich schildern, wo diese überhaupt zu finden sind. Man wählt die SQL-DataSource aus. Rechts im Property-Fenster findet man unten "UpdateQuery" . In das Feld rechts daneben klicken und ganz rechts erscheint ein Button. Diesen Button klicken und ein neues Fenster öffnet sich. Hier werden alle Parameter aufgelistet. Nun zu den Attributen: Für den PK als ParameterSource "Control" wählen. Als Quelle wird die ID der GridView angegeben. Nun auf "advanced Properties" klicken. Bei "PropertyName" "DataKeys" auswählen. Richtig, zum Schluß muß das GridView-Property "DataKeyNames" noch den Namen des PK-Feldes gesetzt bekommen. Im aspx-Code sieht es dann so aus: <UpdateParameters>
Schlußbemerkungen Eigentlich werden die SQL-Anweisungen im Dataset gar nicht mehr benötigt. Durch die benutzerdefinierten Funktionen werden diese nicht mehr angefahren. November 22 Fading MessageBox ohne ButtonsHi, |
|
|