Office Day Oktober 27.10.2014

Svenja Henß
Svenja Henß, Senior Assistant

Wie immer startete letzte Woche Freitag der monatliche Office Day mit Werners Business Update.

Danach ging es mit folgenden Break-Out Sessions weiter:

- Angular JS
- Schlanke Softwarearchitekturen mit Web API
- SSIS Unittesting
- Testing mit CodesUI

IMG_7809IMG_7813IMG_7814IMG_7816IMG_7817IMG_7819IMG_7825IMG_7823

Share |

SDX TC: SQL Server 2012/2014 – Mehr als nur Migration 23.10.2014

Simone Franz
Simone Franz, Marketing Manager

Herzlich lade ich Sie zum SDX Technical Council “SQL Server 2012/2014 – Mehr als nur Migration” ein:

Termin: Donnerstag, der 13. November 2014 ab 17:00 Uhr in München
Zielgruppe: BI/SQL-Entwickler, Architekten, Projektleiter
Dresscode: Business Casual

Agenda:

17:00 Uhr: Begrüßungskaffee
17:30-19:30 Uhr:

Daten schneller, besser, flexibler mit SQL Server 2012/2014
- Hochverfügbare, performante und sichere Datenbanken
- Columnstore Index
- SQL Server InMemory
- Resource Governor
- Buffer Pool Extensions
- SQL Erweiterungen
- SQL Server Migration

19:30 Uhr: Fingerfood

clip_image002

Das Ende des (extended) Supports des SQL Servers 2005, neue/konsolidierte Hardware oder Innovation – das sind potentielle Treiber für eine Migration der SQL Server Infrastruktur.Dabei entstehen nicht nur Kosten und Risiken, sondern eine Migration liefert ebenfalls Mehrwert, z.B. die Konsolidierung von Umgebungen, weniger Hardware- und Supportaufwand, performantere Umgebung sowie die Nutzung neuer Features.

In unserem Technical Council – mit Fokus auf Datenbank-Infrastruktur und
-Entwicklung – zeigen wir Ihnen die Vorteile auf, die eine nicht nur technische Migration von SQL Server 2005/2008 auf 2012/2014 mit sich bringt. In mehreren Live-Demos gehen wir dabei auf typische Anwendungsszenarien ein.

Zum Abschluss geben wir Ihnen eine kurze Empfehlung bzgl. eines Vorgehens bei einer anstehenden Migration und informieren Sie, mit welchen Quick Wins Sie am schnellsten innerhalb Ihres Unternehmens und gegen­über dem Management punkten können.

Beim abschließenden Abendessen können Sie sich dann in lockerer Atmosphäre mit den Teilnehmern und den SDX eXperts zu Features und Einsatzszenarien austauschen.

Das SDX-Team freut sich auf Ihren Besuch.
Auf Wiedersehen im SDX Büro am 13. November 2014 in der Landwehrstraße 61 in München.

Die komplette Einladung bzw. die Teilnahmebedingungen für München erhalten Sie hier.

Share |

LINQ Coding Guidelines #1–Null-Werte für Enumerationen

Alexander Jung
Alexander Jung, Chief eXpert

Das Problem ist beschrieben, die theoretischen Grundlagen sind aus den Füßen, kommen wir also zur ersten Empfehlung bzgl. des Schreibens von LINQ-Ausdrücken…

Empfehlung Artikel 1 des Grundgesetzes zur LINQ-Programmierung:
”null” ist kein zulässiger Wert für Enumerationen! Zuwiderhandlungen werden mit Exceptions in Produktion bestraft.

 

Die null hat im Universum funktionaler Programmierung schlicht und einfach keinen Platz.

“Code written in the functional style is often safer and easier to reason about. For example, functional languages avoid using the null value.” (“F# and Functional Programming”)

“The null value is not normally used in F# for values or variables.” (Null Values (F#))

“I think the succinct summary of why null is undesirable is that meaningless states should not be representable.” (“Best explanation for languages without null”)

Unter anderem ist diese Garantie die Grundlage dafür, dass eine Verkettung von Aufrufen, wie sie zu LINQ gehören, überhaupt erst valide ist:

   1: IEnumerable<int> numQuery2 = numbers.Where(num => num % 2 == 0).OrderBy(n => n);

Ohne diese Garantie müsste der defensive Entwickler jeden Aufruf in dieser Kette einzeln machen und auf null prüfen:

   1: IEnumerable<int> numQuery2 = numbers.Where(num => num % 2 == 0);
   2: if (numQuery2 != null)
   3:     numQuery2 = numQuery2 .OrderBy(n => n);

Das würde dem Ganzen etwas die Eleganz nehmen…

 

Meistens bekommt man Enumerationen und verarbeitet diese weiter. In diesem Fall profitiert man einfach nur und muss das schon mutwillig kaputt machen. Manchmal muss man jedoch die Enumeration initial produzieren, z.B.:

   1: public IEnumerable<Orderbook> GetAll()
   2: {
   3:     IEnumerable<Orderbook> result = null;
   4:     if (User.IsAdmin(user))
   5:         result = _context.OrderbookSet;
   6:     // [...]
   7:     return result;
   8: }

Genau hier fällt das Kind in den Brunnen wenn die Berechtigungen nicht passen. Ein einfacher Aufruf wie…

   1: var candidates= Orderbook.GetAll().Where(ob => ob.Location == "Frankfurt");

… ist damit nicht mehr machbar.

 

Korrekt wäre hingegen:

   1: public IEnumerable<Orderbook> GetAll()
   2: {
   3:     IEnumerable<Orderbook> result = Enumerable.Empty<Orderbook>();
   4:     if (User.IsAdmin(user))
   5:         result = _context.OrderbookSet;
   6:     // [...]
   7:     return result;
   8: }

Wenn der Aufrufer keine Berechtigung hat die Daten zu sehen, bekommt er immer noch eine Enumeration, nur enthält diese eben keine Elemente.

Etwas umständlicher wird das, wenn man mit dem Entity Framework gegen IQueryable arbeitet, denn Queryable bietet keine Pendant zu Empty() an. Wohl aber eine Methode AsQueryable(), die ich verwenden kann, um ein IEnumerable zu “casten”:

   1: public IQueryable<Orderbook> GetAll(string userName)
   2: {
   3:     IQueryable<Orderbook> result = Enumerable.Empty<Orderbook>().AsQueryable();
   4:     if (User.IsAdmin(user))
   5:         result = _context.OrderbookSet;
   6:     // [...]
   7: }

Es ist also nicht notwendig, extra eine Collection anzulegen, wie ich das auch schon gesehen habe:

   1: IQueryable<Orderbook> result = new List<Orderbook>().AsQueryable();

 

Da der C#-Compiler nicht wissen kann, dass eine Methode funktionalen Erfordernissen Rechnung tragen muss, kann er den Entwickler hier leider nicht unterstützen.
Daher liegt diese Anforderung nur in Form einer Konvention vor, die der Entwickler selbst einzuhalten hat – unter Androhung von Strafe. ;-)

Share |

.NET ist dein kleines Einmaleins? Jetzt eXpert werden! 20.10.2014

Svenja Henß
Svenja Henß, Senior Assistant

Dein Herz schlägt für gute Software auf Basis der Microsoft Application Plattform? Für dich gehören zu Business Apps mehr als nur schöne Frontends?

Dann solltest du dir unser Jobangebot näher anschauen:

DEV-Stellenanzeige

Wir suchen Verstärkung für unsere Teams in Frankfurt oder München. Offene Positionen vom Junior bis zum Chief Level.

Unsere Projekte sind regional begrenzt, das heißt du kannst den Feierabend mit Familie und Freunden verbringen und schläfst abends zu Hause im eigenen Bett und nicht im Hotel. Smiley

Ich freue mich auf eure Bewerbungen. Bitte direkt an Svenja.Henss@sdx-ag.de.

Share |

LINQ Coding Guidelines–Definition 15.10.2014

Alexander Jung
Alexander Jung, Chief eXpert

Im letzten Beitrag habe ich Coding Guidelines Hinweise für besseren Code für LINQ versprochen.

Bevor wir allerdings dazu kommen ist es angebracht, zu definieren, worum es eigentlich geht: Was ist mit “LINQ” bzw. “Language Integrated Query” gemeint?

Dazu gibt es tatsächlich sehr unterschiedliche Auffassungen, daher macht diese Klärung durchaus Sinn.

Die übliche Einführung von LINQ beginnt immer mit der Darstellung einer Abfrage in Query-Syntax, z.B.:

   1: var numQuery =
   2:     from num in numbers
   3:     where (num % 2) == 0
   4:     select num;

Auch die allermeisten Beispiele von Microsoft bedienen sich der Query-Syntax.

Das führt dann gelegentlich zu der Idee, dass LINQ gleichbedeutend mit der Verwendung der Schlüsselwörter from, where, select und so weiter sei. Die C# Coding Guidelines von Aviva bauen gar auf dieser Ansicht auf und definieren genau dazu eine Regel:

AV2220 Avoid LINQ for simple expressions 

Rather than

    var query = from item in items where item.Length > 0;

prefer using the extension methods from the System.Linq namespace.

    var query = items.Where(i => i.Length > 0);

Since LINQ queries should be written out over multiple lines for readability, the second example is a bit more readable.

(Hervorhebungen von mir.)

Als ob die zweite Darstellung kein LINQ wäre…

 

Um’s ganz deutlich zu sagen:

LINQ ist mehr, als die Verwendung von ein paar Schlüsselwörtern!

Zu LINQ gehören…

  • Diverse Sprachbestandteile und unterstützende Interfaces
  • Bibliotheken
  • Theoretischer Unterbau

 

Sprachbestandteile

Zunächst ist herauszustellen, dass Query-Syntax und Method-Syntax (also der Verwendung entsprechender Extension Methods) als äquivalent – also beide als valides LINQ – anzusehen. Microsoft ist da selbst ziemlich deutlich:

“[…] the query syntax must be translated into method calls for the .NET common language runtime (CLR) […] You can call them directly by using method syntax instead of query syntax.

Daneben hat es einen ganz praktischen Grund, die Method-Syntax nicht herabzuwürdigen: Die Schlüsselwörter der Query-Syntax bieten nur eine begrenzte Menge an Möglichkeiten und sind nicht erweiterbar. Abfragemöglichkeiten die darin nicht vorgesehen sind kann man daher nur über die Method-Syntax erreichen.

Beispiele dazu gab und gib es zur Genüge: Skip() und Take() um Ausschnitte des Resultsets auszuwählen, First() und Last() um einzelne Werte zu entnehmen, Aggregatfunktionen wie Sum(), komplexere Sortierungen, Umwandlungen mit ToArray(), und so weiter.

Damit haben wir dann die Extension Methods für IEnumerable von Enumerable im Boot.

Aber auch die Einschränkung darauf wäre zu kurz gegriffen, denn damit würden Querable and ParallelEnumerable unter den Tisch fallen. Also sind wir bei Extension Methods als generelles Sprachmittel (wenn auch für einen speziellen Anwendungsbereich) angelangt.

Auf Ebene der Sprachmittel kommen dann noch einige Dinge hinzu, die mit LINQ zusammenspielen, teilweise wegen LINQ überhaupt erst in C# aufgenommen wurden:

Nicht mit LINQ zusammen eingeführt, aber mittelbar damit zusammenhängend sind außerdem:

Teilweise werden diese Sprachmittel durch Interfaces, Idiome und Basisimplementierungen in der BCL unterstützt. IEnumerable und Enumerable sind sicher die hervorstechendsten Beispiele.

Bibliotheken

Auf der anderen Seite kommt dann noch die Unterstützung durch Bibliotheken hinzu, um diverse Datenquellen verfügbar zu machen. Anders ausgedrückt, die Umsetzung von LINQ-to-XY in Form von LINQ-Providern. Besondere Bedeutung haben hier LINQ-to-Objects als kanonische Implementierung und für VB.NET LINQ-to-XML, weil es direkt vom Compiler unterstützt wird.

Theorie

Ein wichtiger Punkt, der gerne vergessen wird: LINQ ist eine Spielart funktionaler Programmierung, was dem Ganzen einen soliden theoretischen Unterbau gibt. Dazu zählen zum Beispiel zu folgende Themen:

Wer hier tiefer einsteigen will, dem sei F# empfohlen.

Fazit

Damit haben wir das theoretische Fundament, nicht unerhebliche Teile des C#/VB.NET-Sprachumfangs, Interfaces und Klassen die das unterstützen, sowie weitere Bibliotheken für Datenquellen im Boot. Und das zudem in einem flexiblen, offenen System, denn Extension Methods oder LINQ Provider lassen sich nach Belieben ergänzen.

Das ist LINQ – nicht ein paar SQL-artige Schlüsselwörter.

 

PS: Bitte keine Irritationen wegen der wiederholten Erwähnung von VB.NET. Das war das letzte mal, versprochen ;-)

Share |

LINQ Coding Guidelines–”Error not found” 09.10.2014

Alexander Jung
Alexander Jung, Chief eXpert

Es gibt sie einfach nicht: Coding Guidelines für LINQ.

Eigentlich ist das verwunderlich, denn für C# im allgemeinen haben wir mehr als genug Auswahl: Automatische Code-Formatierung in Visual Studio, diverse Coding Guidelines als Dokumentation (msdn, lh), StyleCop zur Prüfung.

Und alle ignorieren LINQ.

 

Eine unmittelbare Konsequenz daraus sehe ich immer wieder: Komplexe LINQ-Ausdrücke die an Unlesbarkeit kaum zu überbieten sind; deren Logik sich nur durch “mind compiling and execution” erfassen lässt – sprich, man muss sie gedanklich durchkompilieren und ausführen um sie zu verstehen; einfache LINQ-Ausdrücke, die sich alle Mühe geben, komplex zu erscheinen.

Und das, obwohl LINQ doch eigentlich als deklaratives Sprachmittel der Hort der Lesbarkeit sein sollte.

Ein schönes Beispiel hat Luke mit seinem RayTracer, auch wenn er das zugegebenermaßen nur als Experiment ansieht.

Doch auch vergleichsweise moderate LINQ-Ausdrücke lassen sich oft in ihrer Lesbarkeit deutlich verbessern. Das folgende Beispiel stammt aus einer Beispielanwendung eines Kollegen (mit dessen Einverständnis ich das hier verwende ;-)):

   1: public ApiExpert Get(int id)
   2: {
   3:     return this.db.eXperts
   4:         .Where(x => x.Id == id)
   5:         .ToArray()
   6:         .Select(x => new ApiExpert
   7:                         {
   8:                             Id = x.Id,
   9:                             IsAdmin = x.IsAdmin,
  10:                             Name = x.Name,
  11:                             CustomerResponse = x.CustomerStatements
  12:                                                     .Select(c =>
  13:                                                         new KeyValuePair<string, string>(
  14:                                                             c.Id.ToString(CultureInfo.InvariantCulture),
  15:                                                             c.Statement))
  16:                         })
  17:         .FirstOrDefault();
  18: }

Der folgende Ausdruck ist aus einem Kundenprojekt (anonymisiert, um die Schuldigen zu schützen):

   1: return (from item in repository.ServersThisApplicationDependsOn
   2:         where (item.CONSUMING_APPLICATION == applicationId) && (includeWithdrawn || (item.DEPENDENCY_STATUS != WithDrawnIdentifier))
   3:         orderby item.SERVER_NAME
   4:         select item).AsEnumerable().Select(item => new
   5:         {
   6:             item.CONSUMING_APPLICATION,
   7:             item.SERVER_NAME,
   8:             item.DEPENDENCY_STATUS,
   9:             item.SERVER_STATUS,
  10:             item.SERVER_OS,
  11:             item.SERVER_LOCATION,
  12:             item.SERVER_FQDN,
  13:             LATEST_TARGET_HARDWARE_REMOVAL_DATE = GetFormatedNullableDateTime(item.LATEST_TARGET_HARDWARE_REMOVAL_DATE)
  14:         });

Dito der Code aus der Suchseite einer Anwendung:

   1: var condition = LinqHelper.True<EntityModel.Transaction>();
   2: var conditionBalance = condition.And(t => (((searchCriteria.MinimumAmount == null) || (t.Amount >= searchCriteria.MinimumAmount)) &&
   3:                                           ((searchCriteria.MaximumAmount == null) || (t.Amount <= searchCriteria.MaximumAmount))));
   4: var conditionDate = conditionBalance.And(t => (((searchCriteria.StartDate == null) || (t.Date > searchCriteria.StartDate.Value.AddDays(-1))) &&
   5:                                               ((searchCriteria.EndDate == null) || (t.Date < searchCriteria.EndDate.Value.AddDays(1)))));
   6: string transactionType = GetTransactionType(searchCriteria.CashTransactionType);
   7: var conditionTransactionType = conditionDate.And(t => ((searchCriteria.CashTransactionType == TransactionType.All) || (transactionType == t.Type)));
   8:  
   9: result = entities.Transaction
  10:     .Join(
  11:         entities.Account.Where<Account>(ac => ac.AccountID == accountId),
  12:         t => t.Account.AccountID,
  13:         a => a.AccountID,
  14:         (t, a) => t)
  15:        .Where(conditionTransactionType.Compile());

Zur schlechten Lesbarkeit kommen hier noch Bugs.

 

Beispiele für schlecht lesbaren LINQ-Code gibt es also zuhauf. Bei Guidelines, wie man das verbessern kann, wird es hingegen dünn:

  • Es gibt einige wenige StyleCop-Regeln (SA1102-SA1105)
  • C# Coding Conventions (C# Programming Guide) hat im Abschnitt “LINQ Queries” ein paar sehr grundlegende Ratschläge, kratzt damit aber nur an der Spitze des Eisbergs.
  • Die 101 LINQ Samples folgen einer einheitlichen Formatierung, ohne diese allerdings zu beschreiben. Außerdem sind sie als Beispielcode nicht immer der beste Ratgeber für Implementierungen in einem Projekt, da sie sich üblicherweise auf genau einen Aspekt konzentrieren.

Dummerweise gibt es auch schlechte Ratschläge, etwa:

 

Jetzt wäre es an der Zeit, dass ich mit Coding Guidelines für LINQ dagegenhalte. Allerdings sprechen zwei Dinge gegen dieses Vorgehen:

  1. Der Beitrag wird zu lang ;-)
  2. Ich habe keine schlüsselfertigen Coding Guidelines. (Sorry!)

Was ich aber habe sind eine ganze Reihe von Hinweisen, wie man es besser machen kann. Auslöser sind dabei immer reale Probleme, die mir in Reviews untergekommen sind.

DISCLAIMER: Die Beispiele, die ich hier und in den folgenden Beiträgen zeige, entstammen – soweit nicht anders angegeben – realen Projekten. Sie wurden von mir lediglich anonymisiert (um die Schuldigen zu schützen ;-)) und ggf. gekürzt, wenn es der Sache dient.

Wer das in seine Coding Guidelines einfließen lassen will ist natürlich willkommen.

Share |

Advanced T-SQL: OUTPUT und $IDENTITY 06.10.2014

Matthias Pohl
Matthias Pohl, IT-Consultant
Wenn innerhalb des Microsoft SQL-Servers neue Daten in eine Tabelle mit einer Identitätsspalte eingefügt werden, stellt sich häufig folgende Frage: Wie können am effektivsten die neuen ID-Werte der zuletzt eingefügten Datensätze ermittelt werden?
 
Der folgende Flurfunkartikel repräsentiert einen weiteren Teil einer kleinen Serie zum Thema "Advanced T-SQL", zu welchem bereits die Artikel Advanced T-SQL: ISNULL vs. COALESCE und Advanced T-SQL: WITH TIES erschienen sind.
 
Die eben beschriebene Problemstellung soll im Beitrag zunächst anhand einfacher T-SQL-Code-Beispiele dargelegt werden. Anschließend werden durch Einsatz der OUTPUT-Klausel elegante Lösungsansätze aufgezeigt.
Neue Werte in Identitätsspalte einfügen

Per Default wird der Wert einer Identitätsspalte nach Absetzen des INSERT-Befehls automatisch ermittelt. Wird beispielsweise folgende Tabellenstruktur

   1: CREATE TABLE [TblExpert]
   2: (
   3:     [ExpertID] INT IDENTITY(1, 1) NOT NULL,
   4:      [Name] NVARCHAR(MAX) NOT NULL,
   5:     [Nachname] NVARCHAR(MAX) NOT NULL
   6: );

verwendet und anschließend ein INSERT-Statement in der Form

   1: INSERT INTO TblExpert(Name, Nachname) VALUE ('Matthias', 'Pohl');

auf die neu angelegte Tabelle abgesetzt, so kann mit einer geeigneten Abfrage, z.B.

   1: SELECT [ExpertID], [Name], [Nachname]
   2: FROM [TblExpert]
   3: WHERE [ExpertID] = 
   4: (
   5:     SELECT MAX([ExpertID])
   6:     FROM [TblExpert]
   7: );

der neue Datensatz mit der ID-Spalte (hier im konkreten Fall: “[ExpertId]”) ermittelt werden.

Die nachfolgende Abbildung zeigt das Ergebnis der Abfrage:
image3_thumb
 
Der Nachteil bei diesem Verfahren ist, dass – ohne Kenntnis des CREATE-Statements zur Tabelle – die “[ExpertId]”-Spalte nicht automatisch als Identitätsspalte erkannt wird. Des Weiteren muss sowohl für das Einfügen als auch das anschließende Auslesen der Daten jeweils einmal auf die Datenbank zugegriffen werden. Wird zusätzlich noch berücksichtigt, dass ohne Transaktionsblock um das INSERT- und SELECT-Statement zusätzlich Dateninkonsistenzen durch Nebenläufigkeit bzw. Parallelität entstehen können, zeigt sich sehr schnell, dass diese Variante der Wertermittlung für die ID-Spalte nicht sonderlich geeignet ist.
 
Systemfunktionen für Identitätsspalte
Um Identitätsspalten auszulesen, bietet der SQL-Server nun einige Systemfunktionen an. Die bekanntesten sind hierbei sicherlich: 
Mit vorangestelltem SELECT-Schlüsselwort kann durch diese Funktionen der neu eingefügte Wert der Identitätsspalte ermittelt werden.
Doch auch die Verwendung dieser Systemfunktionen birgt einige Nachteile. Die oben aufgeführten Funktionen im SQL-Server können durch zusätzliche mögliche Schreiboperationen signifikant beeinflusst werden. Hierzu zählen insbesondere parallele Datenbank-Zugriffe ohne Transaktionskontrolle sowie möglicherwiese ausgelöste Trigger-Aktionen.
 
Wird beispielsweise für die [TblExpert]-Tabelle ein Trigger in der Form
   1: CREATE TRIGGER TblExpertAfterInsert
   2: ON [TblExpert]
   3: AFTER INSERT
   4: AS 
   5: BEGIN
   6:     IF TRIGGER_NESTLEVEL() > 1 RETURN
   7:     
   8:     INSERT [TblExpert] 
   9:     (Name, Nachname)
  10:     SELECT Name+'2', Nachname+'2' FROM Inserted;
  11: END
 
hinterlegt und werden anschließend die folgenden beiden SQL-Statements ausgeführt
   1: INSERT INTO TblExpert(Name, Nachname)
   2: VALUES ('Matthias', 'Pohl');
   3:  
   4: SELECT 
   5: @@IDENTITY AS '@@IDENTITY', 
   6: SCOPE_IDENTITY() 'SCOPE_IDENTITY()', 
   7: IDENT_CURRENT('[TblExpert]') AS 'IDENT_CURRENT(''[TblExpert]'')';
so liefern die oben erwähnten Systemfunktionen, wie in der folgenden Abbildung dargestellt, unterschiedliche Werte:
 
image
 
Des Weiteren wird auch hier, wie im vorrangegangen Beispiel, beim Ermitteln des Wertes ein zweiter (unnötiger) Lesezugriff auf die Datenbank erfordert.
Die folgende Abbildung, welche die Message-Konsole des SQL-Server Management Studios zeigt, legt dar, dass sowohl für den INSERT- als auch den anschließenden SELECT-Befehl jeweils ein Zugriff erfolgt:
image_thumb2
 
Verwendung der OUTPUT-Klausel
Datenmanipulationsbefehle (kurz: DML-Anweisungen) wie MERGE, INSERT, UPDATE oder DELETE sind hauptsächlich für das Bearbeiten und Verändern von Datensätzen konzipiert worden. Durch Einsatz der OUTPUT-Klausel können jedoch zusätzlich (und quasi gleichzeitig) noch Datensätze mit zurückgegeben werden. 
Als Beispiel dient folgende Einfüge-Operation, welche sich am obigen Szenario orientiert und das $IDENTITY-Schlüsselwortes/-Prädikats verwendet:
   1: INSERT INTO TblExpert([Name], [Nachname]) 
   2: OUTPUT INSERTED.$IDENTITY
   3: VALUES ('Matthias', 'Pohl');
 
Mit Hilfe der OUTPUT-Klausel und des $IDENTITY-Prädikats innerhalt des obigen SQL-(INSERT)-Statements können mittels Zugriff auf die INSERTED-Tabelle durch eine einzige atomare SQL-Anweisung neue Datensätze eingefügt und zeitgleich die neu eingefügten Werte in der ermittelt werden. Hierfür sind keine(!) weiteren Lesezugriffe auf der Datenbank und somit auch keine Zugriffskontrolle notwendig, der Zugriff auf die Datenbank erfolgt hier nur einmal.
 
Als Ergebnis des obigen INSERT-Statements wird folgender Datensatz zurückgegeben:
image_thumb41
Des Weiteren werden keine zusätzlichen Funktionaltäten (z.B. komplexe Aggregationen etc.) gegenüber einem INSERT-Statement  ohne OUTPUT-Klausel benötigt. Die folgende Abbildung, welche den Ausführungsplan eines INSERT-Statement mit und eines ohne OUTPUT-Klausel gegenüber stellt, belegt dies: 
image_thumb4
 
Fazit
Der Artikel zeigt den Einsatz der OUTPUT-Klausel vorrangig anhand von einfachen INSERT-Befehlen  für Tabellen mit Identitätsspalte. Der Einsatzes des OUTPUT-Schlüsselworts offeriert jedoch noch weitere Vorteile. Zum einen kann er auch für MERGE-, DELETE- und UPDATE-Statements verwendet werden und zum anderen funktioniert er auch wenn eine T-SQL-Anweisungen Einfluss auf mehrere Datensätze, z.B. multipler INSERT-Befehl, hat. Dann können nämlich sämtliche neu eigefügte Datensätze ermittelt werden.
 
Quellen
Share |