Stored Procedure mit skalaren Rückgabewert im Entity Framework

Will man Stored Procedures über das Entity Framework aufrufen, kann man das – wenn man denn ein EntitySet erwartet – recht einfach. Erwartet man aber eine skalare Variable (Int32, String, Guid…) weiter als Response, gibt es leider ein bekanntes Problem, dass dafür kein Code generiert wird.

Um dennoch eine solche Procedure verwenden zu können, müssen einige Einträge in dem Model von Hand getätigt und im Code muss eine eigene EntityConnection implementiert werden, die für den StoredProcedure-Aufruf eine temporäre Verbindung aufbaut. Um das zu verdeutlichen, hier meine Herangehensweise in einem Testprojekt.

In der Datenbank erstelle ich mir vorerst eine Stored Procedure namens GetPersonenId. Diese Procedure erwartet zwei Parameter, zum einen eine Id, und zum anderen einen boolschen Wert. Was genau in der SP passieren soll, ist für dieses Beispiel nicht relevant.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
USE [TestDB2]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[GetPersonenId]
	@Root uniqueidentifier ,
	@Rekursiv bit
AS
BEGIN
	SET NOCOUNT ON;
 
	If @Rekursiv = 0
	BEGIN
		select PersonenId
		from Personen
		where ChildId = @Root
	End
 
	Else
	Begin
		-- rekursive abfrage...
	End
END

Nun füge ich meinem Projekt ein ADO.NET Entity Data Model hinzu und wähle aus meine Datenbankverbindung meine Datenbank aus.

Im kommenden Dialog wähle ich hier unter den “Gespeicherten Prozeduren” meine SP aus.

Das nun erstellte Model schliesse ich und öffne das auch gleich wieder mit den integrierten XML-Editor, dazu ein Rechtsklick auf das Model im Projektmappen-Explorer und auf “Öffnen mit…” Hier wähle ich dann den XML Editor zum öffnen des Modells.

Hier findet man den generierten Code kommentiert mit den jeweiligen Bereichen (SSDL, CSDL, C-S mapping). Im Knoten edmx:StorageModels (SSDL content)  sollte bereits, eine vom EF definierte Funktion existieren, die den Namen der Procedure trägt.

1
2
3
4
<Function Name="GetPersonenId" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="false" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo">
  <Parameter Name="Root" Type="uniqueidentifier" Mode="In" />
  <Parameter Name="Rekursiv" Type="bit" Mode="In" />
</Function>

Die kann so belassen werden. Im Knoten edmx:ConceptualModels (CSDL content) fügen wir ein FunktionImport Knoten hinzu, der den Rückgabetypen und die Parameter wie diese in der StoredProcedure definiert wurden. Wenn der Knoten EntityContainer kein schliessendes Tag hat sondern /> endet, muss dieser so geändert werden.

1
2
3
4
<FunctionImport Name="GetPersonenId" ReturnType="Collection(Guid)">
  <Parameter Name="Root" Type="Guid" Mode="In" />
  <Parameter Name="Rekursiv" Type="Boolean" Mode="In" />
</FunctionImport>

Im Knoten edmx:Mappings (C-S mapping content) ergänzen wir im Knoten EntityContainerMapping den Knoten FunctionImportMapping. Der kommende FunctionName im Code  ist der im Schema definierte Namespace plus der Name von der SP. Auch hier wichtig, wenn der Knoten EntityContainerMapping kein schliessendes Tag hat sondern /> endet, muss dieser so geändert werden.

1
<FunctionImportMapping FunctionImportName="GetPersonenId" FunctionName="PersonenModel.Store.GetPersonenId" />

Das edmx-File kann nun gespeichert und geschlossen werden und wir wechseln in die Klasse wo wir die Methode bauen möchten, die die Prozedur  aufruft. Jetzt verweisen wir noch auf System.Configuration um den ConfigurationManager für die Übergabe des ConnectionStrings aus der App.Config. Der Connectionstring kann aber auch direkt in die Variable connection geschrieben werden…

Hier nun der Code, in den Kommentare werden die einzelnen Zeilen kommentiert.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public static IEnumerable<Guid> ReadPersonenIdStruktur(Guid root, bool recursive)
{
    //Liste instanziieren
    var personen = new List<Guid>();
 
    //connectionstrring aus der app.config holen
    string connection = ConfigurationManager.ConnectionStrings["PersonenEntities"].ConnectionString;
 
    //context verwenden
    using (var conn = new EntityConnection(connection))
    {
        try
        {
            //connection oeffnen
            conn.Open();
 
            //EntityCommand instanzieren
            EntityCommand cmd = conn.CreateCommand();
 
            /* der comandtext setzt sich aus den entities-namen der
             * bei der Erstellung des Models festgelegt wurde
             * plus den Namen der Stored Procedur                     *
             */
            cmd.CommandText = "PersonenEntities.GetPersonenId";
 
            //commandtype festlegen
            cmd.CommandType = CommandType.StoredProcedure;
 
            //die parameter die erwartet werden von der sp dem Kommando hinzufuegen
            cmd.Parameters.AddWithValue("Root", root);
            cmd.Parameters.AddWithValue("Rekursiv", recursive);
 
            //ausfuehren
            var result = cmd.ExecuteReader(CommandBehavior.SequentialAccess);
 
            //ergebnisse in die liste schreiben
            while (result.Read())
            {
                personen.Add((Guid)result.GetValue(0));
            }
        }
        catch (Exception ex)
        {
            //Fehlerbehandlung
        }
        finally
        {
            //connection schliessen und wegschmeissen
            conn.Close();
            conn.Dispose();
        }
    }
    return personen;
}

Wenn noch Fragen offen sind, versuche ich zu helfen. Ansonsten wie immer,

viel Spass beim entwickeln : )




Kick it on dotnet-kicks.de

Einträge im Wörterbuch von OneNote editieren

Es kommt sicher mit der Zeit mal vor, dass sich so das eine oder andere falsche Wort in das Wörterbuch “schummelt”, welches man da gerne wieder raus haben oder editieren möchte.

In OneNote geht das nicht über den Weg, wie man das unter Word gewohnt ist (Extras/Optionen/Wörterbuch-Rechtschreibung). Hier liegt es eigentlich direkt vor der Nase sozusagen : )

Man geht über das Menü Extras / Rechtschreibung auf Rechtschreiboptionen.

und im öffnenden Dialog auf den Button “Benutzerwörterbücher…”

hier nun das Wörterbuch welches man verwendet, in meinem Fall das Standardwörterbuch “custom.dic” markieren und auf den Button “Wortliste bearbeiten…” klicken.

Im folgenden Dialog dann, sind die Wörter zu finden, die man – ja leider – nur löschen kann. Möchte man ein Wort editieren, muss man das löschen und neu hinzufügen…

Aber wie auch immer, ob nun löschen oder editieren, halte einfach dein Wörterbuch auf den aktuellen Stand : )



Kick it on dotnet-kicks.de

Elegante History in der Eingabeaufforderung

Hast du das schon gewusst? Wenn man in der Eingabeaufforderung die F7 Taste drückt, erscheint ein “Dialog” und man kann erneut aus den letzten Eingaben wählen.

Nun arbeite ich schon wirklich sehr lange mit Windows und wusste das nicht. Ich hatte mich immer nur mit der “Pfeil nach Oben” Taste bemüht : )



Kick it on dotnet-kicks.de

Explorer.exe mit Arbeitsplatz öffnen | Windows7 Quicky

Wenn man normalerweise auf den ExplorerButton in der Taskleiste klickt, wird man direkt zu den Bibliotheken verwiesen. Will man hier aber lieber den Arbeitsplatz öffnen, dann klickt man in der Taskleiste das Explorer-Icon mit der rechten Maustaste, geht dann auf Windows-Explorer wieder mit der rechten Maustaste und dann auf Eigenschaften.

Hier kann dann der Zielpfad beliebig angepasst werden.

Um auf den Arbeitsplatz (Computer) zu verweisen trägt man hier bei Ziel

%SystemRoot%\explorer.exe /e,

ein (Kommata am Ende wichtig!). Weiterhin können auch alle verfügbaren Umgebungsvariablen verwendet werden. Wenn man z.B.

%WinDir%\explorer.exe %UserProfile%

unter dem Zielpfad einträgt, öffnet ein Klick auf den Explorer-Icon das Benutzerverzeichnis.

Also, den Explorer starten wie es gefällt… probiere es einfach aus : )




Kick it on dotnet-kicks.de

VSTO & PIA 2003 in einem Office 2003 Setup

Das Deployen eines Word Add-In für Office 2003 hat echt Nerven gekostet. Das Add-In wollte sich einfach nicht innerhalb von Word 2003 anzeigen lassen.

Zudem war es auch noch recht mühsam, da das Add-In sowohl für Word 2003 als auch für Word 2007 laufen soll. Ich kam also nicht herum, das 2003er Add-In in einer virtuellen Umgebung zu entwickeln und in einer weiteren VM mit einer sauberen XP und Office 2003 Prof. Installation das Add-In zu testen.

Okay das war aber nicht das eigentliche Problem, sondern dass ich es anfänglich nicht gebacken bekommen habe, das Add-In zum laufen zu bekommen.

Wo waren die Probleme?

Um Herauszubekommen, was denn das Problem sein könnte habe ich das Tool von Microsoft namens PSS VSTO 2005 Client Troubleshooter gefunden, diese App zeigt DLLs an die nicht installiert sind und wohlmöglich für das Ausführen eines Add-Ins notwendig sind.

Ich hatte kein VSTO SE für Office 2003 installiert. Okay nachinstalliert.
Ich hatte keine PIA für Word 2003 installiert. Okay nachinstalliert.

Aber eigentlich will man die erforderlichen Komponenten ja nicht vom Endbenutzer nachinstallieren lassen, sondern die Setup, welche das Add-In installieren soll, sollte diese ja im Grunde schon beinhalten.

Nun, wenn man in einem Setup-Projekt auf die Eigenschaften geht, kann man ja so einige Komponenten anklicken, die für ein Setup erforderlich sein sollen.

Leider findet man hier vergebens die beiden erforderlichen Komponenten, was also tun? Nach einer Weile Recherche kommt man so auf die Stichpunkte Mergemodul und Bootstrapper Package. Letzteres sollte die Lösung sein.

Ich also genau nach der Anleitung versucht jenes Package zu bauen:

ComponentChecker Sample herunterladen und installieren (oder mit 7Zip entpacken) und in den Ordner

Microsoft Visual Studio 2005 Tools for Office SE Resources/VSTO2005SE Windows Installer Sample Version 3/projects/Checks

wechseln. In diesem Ordner befindet sich die Datei ComponentCheck.cpp. Nun mit der Visual Studio Eingabeaufforderung direkt zu diesen Verzeichnis wechseln und folgenden Befehl aufrufen:

cl.exe /Oxs /MT /GS ComponentCheck.cpp advapi32.lib

Erstellt wurde nun eine ComponentCheck.exe und eine ComponentCheck.obj. Die ComponentCheck.exe muss nun nach, für Office2003PIA

Microsoft Visual Studio 2005 Tools for Office SE Resources\VSTO2005SE Windows Installer Sample Version 3\packages\Office2003PIA

Und für  VSTOSERuntime

Microsoft Visual Studio 2005 Tools for Office SE Resources\VSTO2005SE Windows Installer Sample Version 3\packages\VSTOSERuntime

kopiert werden. Laut Anleitung, sollen diese Verzeichnisse anschliessend nach

C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\BootStrapper\Packages

kopiert werden.

Wie im HowTo beschrieben, sollten die Komponenten nun in den erforderlichen Komponenten aufgeführt werden, wurden sie aber nicht *grml*.

Ich weiter recherchiert und nochmals die Anleitung durchgegangen, ob ich nicht irgendwas übersehen habe. Und es war auch so, ich hätte “doch” richtig lesen sollen… “Verwendet man Visual Studio 2008, dann in das Verzeichnis”

C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bootstrapper\Packages

kopieren. Wenn der Pfad bei dir nicht übereinstimmen sollte, der genauer Pfad steht auch im Schlüssel:

HKLM\Software\Microsoft\GenericBootstrapper\4.0

Gesagt, getan und sicherheitshalber Visual Studio nochmal neu gestartet und zu den Komponenten gewechselt. Voila die beiden erforderlichen Pakete wurden nun angezeigt.

So die Setup nun neu gebaut und auf der anderen Kiste ausgeführt. Und ich bin ganz erfreut, das er nun wirklich diese beiden erforderlichen Programme und das Add-In auf dem Zielrechner installiert.

 

Hach ist das ein Gefühl, mal wieder ein Problem gelöst zu haben, “Eine Odyssee” hätte ich beinahe noch im Titel untergebracht… : )



Kick it on dotnet-kicks.de

Seite 5 von 136« Anfang...2345678...Ende »