code it

Martins Tech Blog

Hierarchische Daten löschen

Möchte oder kann man den mit SQL Server 2008 eingeführten Datentyp hierarchyid nicht verwenden, nutzt man meist eine Tabellenstruktur mit den Spalten Id (Identifier des aktuellen Datensatzes) und ParentId (Identifier des Eltern-Datensatzes), um hierarchische Daten abzubilden. Dabei werden diese beiden Spalten durch eine Selbstreferenz miteinander verbunden.

 

Da es sich hier um eine klassische Eltern-Kind-Beziehung handelt, ist man nun versucht, die Referenz mit einer Löschweitergabe (ON DELETE CASCADE) zu erzeugen.

CREATE TABLE [Test].[Category](
	[Id] [int] IDENTITY(1,1) NOT NULL,
	[ParentId] [int] NULL,
	[Name] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_Category] PRIMARY KEY CLUSTERED 
(
	[Id] ASC
),
CONSTRAINT [FK_Category_Category] FOREIGN KEY([ParentId])
REFERENCES [Test].[Category] ([Id]) ON DELETE CASCADE
)
GO

Um es vorweg zu nehmen: Dieses Statement schlägt fehl mit der Meldung:

Msg 1785, Level 16, State 0, Line 1
Introducing FOREIGN KEY constraint 'FK_Category_Category' on table 'Category' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.

Es bleibt also erstmal nichts anderes übrig als die Tabelle ohne CASCADE zu erstellen, in dem Wissen, dass ein Löschversuch eines Elements mit Kindelementen zwangsläufig zu einem Fehler führt, weil dadurch die Kindelemente verwaisen würden.

Die Lösung für dieses Problem ist ein INSTEAD-OF-DELETE-Trigger mit einer rekursiven Abfrage:

CREATE TABLE [Test].[Category](
	[Id] [int] IDENTITY(1,1) NOT NULL,
	[ParentId] [int] NULL,
	[Name] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_Category] PRIMARY KEY CLUSTERED 
(
	[Id] ASC
),
CONSTRAINT [FK_Category_Category] FOREIGN KEY([ParentId])
REFERENCES [Test].[Category] ([Id])
)
GO

CREATE TRIGGER CategoryDeleteTrigger ON [Test].[Category]
INSTEAD OF DELETE
AS
IF @@ROWCOUNT = 0
RETURN;

WITH x
AS
(
	SELECT Id 
	FROM deleted
	UNION ALL
	SELECT c.Id 
	FROM [Test].[Category] c
	INNER JOIN x on x.Id = c.ParentId
)

DELETE [Test].[Category]
WHERE Id IN (SELECT Id FROM x)
GO

Ein kleiner Test zeigt, dass es wie erwartet funktioniert:

Das DELETE-Statement löscht sowohl den betroffenen Datensatz als auch die 5 durch Rekursion ermittelten Datensätze.

Treffen der SharePoint UserGroup Dresden am 11.06.2009

Das nächste Treffen der SharePoint UserGroup Dresden findet am 11. Juni statt. Gastgeber ist diesmal die T-Systems MMS.

Gastredner bei diesem Treffen ist Steffen Krause (Technical Evangelist, Microsoft Deutschland). Er wird aus seinen Erfahrungen über die Grundlagen für den SQL Server in Verbindung mit SharePoint berichten sowie Best Practises für den Betrieb mit SharePoint vorstellen. Das ist auch die optimale Gelegenheit, ihn mit anderen Themen, die Sie gerade bedrücken, zu löchern.

Weitere Informationen und Anmeldung zum Event unter https://www.xing.com/events/346995

Ansprechpartner: Sascha Henning, Martin Hey

Attach-to-Webserver-Makro für Visual Studio

In letzter Zeit mache ich wieder sehr viel Webentwicklung und –debugging. Dabei fand ich es etwas nervig für das Debugging immer die Menüstruktur mit den Punkten Debug -> Attach to Process zu bedienen und dann aus der Liste alle w3wp-Prozesse auszusuchen.

Glücklicherweise gibt es dafür ja die Makro-Funktion. also schnell ein Makro geschrieben:

Imports System
Imports EnvDTE80
Imports System.Windows.Forms

Public Module AttachToWebServer

    Public Sub AttachToWebServer()
        Dim W3WPProcName As String = "w3wp.exe"

        If Not AttachToProcess(W3WPProcName) Then
            MessageBox.Show(String.Format("Process {0} cannot be found", W3WPProcName), "Attach to webserver macro")
        End If

    End Sub

    Public Function AttachToProcess(ByVal ProcessName As String) As Boolean

        Dim Processes As EnvDTE.Processes = DTE.Debugger.LocalProcesses
        Dim Process As EnvDTE.Process
        Dim ProcessFound As Boolean = False

        For Each Process In Processes
            If (Process.Name.Substring(Process.Name.LastIndexOf("\") + 1) = ProcessName) Then
                Process.Attach()
                ProcessFound = True
            End If
        Next

        AttachToProcess = ProcessFound

    End Function
End Module

Damit nun das Makro nicht immer händisch über den Makro-Explorer aufgerufen werden muss, noch schnell ein ein Shortcut dafür vergeben und: Voilà!

Visual Studio Tipp: Shortcut für ein Makro vergeben

Makros erleichtern die Arbeit mit Visual Studio. Doch nicht immer möchte man über den Makro-Explorer erst sein Makro auswählen. Besonders bei häufig benutzten Makros ist es sinnvoll, einen Shortcut zu vergeben. Dazu geht man wie folgt vor:

  1. Unter dem Menüpunkt Tools den Eintrag Options auswählen.
  2. Unter Environment auf Keyboard klicken.
  3. Im Auswahlfeld Show commands containing gibt man nun “macros.” ein. Damit erscheinen hier alle Makros.
  4. Hier markiert man nun das gewünschte Makro.
  5. Im Feld Press shortcut key(s) drückt man nun einmal die Tastenkombination, mit der man das Makro künftig aufrufen möchte – z.B. Strg + Shift + Alt + A
  6. Nachdem man auf Assign und OK geklickt hat, ist der neue Shortcut aktiv.

Die detaillierte Beschreibung gibt es auch nochmal in der MSDN.