Archiv für den Monat März 2013

Entity Framework Webcasts – Stored Procedures und SQL Queries

Im sechsten Teil meiner Entity Framework Webcast Serie zeige ich, wie die IUnitOfWork erweitert werden muss, um SQL Abfragen und Befehle auszuführen. Im Fokus stehen Value Functions und Stored Procedures.

 

 

Dafür stellt das Entity Framework 2 Schnittstellen bereit:

Ein wichtiger Hinweis an dieser Stelle, welcher eingehender in meinem Webcast erwähnt wird: Zum Ausführen einer SQL Query existieren 2 Implementierungen:

Der wesentliche Unterschied besteht darin, dass im ersten Fall die zurückgegebenen Entitäten nicht getrackt werden, im zweiten hingegen schon. Das ist leicht nachvollziehbar, so muss bei DbContext.Database.SqlQuery ein generischer Parameter, der den Rückgabewert darstellt, übergeben werden. Im Falle von DbSet.SqlQuery ist dies nicht nötig, schließlich befindet man sich zum Zeitpunkt der Abfrage auf einem konkreten Set an Entitäten, die über den Context aufgelöst wurden.

Meine vorgestellte Lösung geht den gleichen Weg wie die in Teil 3 beschriebenen Queries, d.h. es werden quasi SQL Query und Command Repositories angelegt, um einer Streuung innerhalb der Anwendungslandschaft entgegenzuwirken.

Schließlich noch zwei Sicherheitshinweise:

  • Die SQL Befehle werden mit den Berechtigungen des Contexts bzw. des darunterliegenden Sicherheitstoken ausgeführt
  • Beim Erstellen des SQL Strings sollte aus Sicherheitsgründen gegenüber Injections mit String.Format() oder alternativ mit SqlParameters gearbeitet werden.

 

I wrote this blog post as an answer of a question from the Netherlands, so I want to complete this article with a quote:

“When you execute a SqlQuery from Database, the results are never tracked by the context, even if the query returns types that are in the model an known by the context. If you do not want the results to be changed-tracked, use DbContext.Databae.SqlQuery.

Results of a DbSet.SqlQuery will be tracked by the context. Ensuring that results are change-tracked is the primary reason you would choose to use DbSet.SqlQuery over Database.SqlQuery.” (Programming Entity Framework, Page 226)

 

Weitere Quellen:

Werbung

Feedback für den Vorgesetzten und den Mitarbeiter

Viele Führungskräfte vergessen entweder die Mitarbeitergespräche für sich persönlich zu nutzen oder sie scheuen die Rückmeldung der Mitarbeiter. Wer schaut schon gerne in den Spiegel, wenn er nicht weiß, was er darin sieht. Damit verlieren sie ein wichtiges Instrument zur eigenen Weiterentwicklung und zur Optimierung der Abteilungsleistung.

Darüber hinaus ist es besonders wichtig die Einstellung der Mitarbeiter zu diesem aus meiner Sicht unverzichtbaren Personalführungsinstrument einzuholen. Ich habe inzwischen festgestellt, dass eine Ablehnung seitens der Mitarbeiter oft darin begründet sein kann, dass der Mitarbeiter gar nicht richtig weiß, worum es geht, wie er sich präparieren muss und wie facettenreich ein Gespräch ablaufen kann. In diesem Kontext kann ich zu einer offenen Einführungsstunde in der Abteilung raten. Idealerweise nimmt man die eigene Schwächen als Gesprächsgrundlage, von denen man weiß, dass diese unter den Mitarbeitern argwöhnisch betrachtet werden. Weiterführendes Material, welches einfach zu konsumieren und schnell zu lesen ist, kann ebenfalls dienlich sein. Bücher wie 30 Minuten Mitarbeitergespräche oder 30 Minuten richtiges Feedback kommen schnell auf den Punkt, wenngleich natürlich der thematisch Tiefgang fehlt, was aber auch zu viel des Guten wäre. Für diejenigen, die tiefer einsteigen wollen, soll diese Empfehlung genannt sein. Mit einem Irrglauben möchte ich an dieser Stelle noch aufräumen: Ein höheres Alter (> 40) ist kein Garant dafür, dass die Person bereits einMitarbeitergespräch geführt hat. Deshalb sollte das noch vor dem eigentlichen Gespräch geklärt werden!

In der oben genannten Empfehlung gibt es auch einen Feedbackbogen für Vorgesetzte. Ich habe diesen vor geraumer Zeit einmal von meinen Kollegen ausfüllen lassen. Generell ermutige ich das über einen anonymen Weg zu ermöglichen.

Nach dem letzten Gespräch im vergangenen Januar ging es mir dann darum, ein Gefühl dafür zu bekommen, wie die Gespräche wahrgenommen werden. Hierin stieß ich im Übrigen darauf, dass eine Person noch der oben genannten Erläuterung bedurfte!

Hier der Fragebogen, den ich mir selbst ausgedacht habe:

  • Wie zufrieden seid ihr mit der Häufigkeit: Skala von 1-10, wobei 10 sehr gut ist
  • Haltet ihr persönlich diese Gespräche für sinnvoll: Skala von 1-10, wobei 10 sehr sinnvoll
  • Denkt ihr, dass ihr selbst noch mehr Zeit in die Vorbereitung stecken solltet: 1-10, wobei 10 bedeutet, dass ihr noch wesentlich mehr Zeit investieren solltet
  • Sollte ich noch mehr Zeit in die Vorbereitung stecken: 1-10, wobei 10 bedeutet, dass sehr gut vorbereitet war
  • Persönliches Fazit über das letzte Gespräch: Skala von 1-10, wobei 10 sehr positiv ist

image

Interessant finde ich persönlich die Selbsteinschätzung! Das könnte darin begründet sein, dass ich regelmäßig darauf hinweise sich Notizen zu machen und sich einmal wieder die letzten Wochen zu betrachten. Wenn dies mehrfach unterjährig unterlassen und erst kurz vor dem Gesprächstermin nachgeholt wird, dann führt das natürlich zu einem schlechten Gewissen.

Feedback zur dotnet pro

Ich bin begeisterter dotnet pro Leser. Aus meiner Sicht ist es die führende deutsche Fachzeitschrift für .NET Entwickler. Durch die Erweiterung des Themengebietes weit über reine .NET Themen hinaus wird inzwischen aber ein wesentlich größeres Publikum angesprochen. Mir ist von vielen IT Firmen bekannt, dass sie ein entsprechendes Zeitschriften Abo besitzen, um es den Mitarbeitern kostenfrei zur Verfügung zu stellen. Wie kürzlich in diesem chip.de – Artikel erläutert, ist das einer von vielen guten Wegen, um die Mitarbeiter als Selbstentwickler zu fördern bzw. darin zu unterstützen. Lebenslanges Lernen wurde von der europäischen Union als elementare Fähigkeit in der heutigen Gesellschaft deklariert.

Im Folgenden will ich 3 Punkte nennen, bei denen ich persönlich noch Optimierungspotential sehe. Diese sollen als konstruktive Kritik an der dotnet pro wahrgenommen werden. Falls ihr das anders seht oder Punkte ergänzen wollte, so beteiligt euch doch in Form von Kommentaren oder Tweets.

 

Aktuell fehlt es noch an einer dedizierten Kindle Ausgabe. Dies soll sich aber laut Aussage von Tilman Börner bis bereits dieses Jahr im Herbst ändern.

Eine bessere Suche im Kundenbereich, die feingranulare Suchkriterien erlaubt: Hierzu möchte ich eine E-Mail veröffentlichen, auf die mir ebenfalls Tilman Börner geantwortet hat.

Guten Tag,

kann man denn auf der Homepage im Archiv auch nach allen Artikel einer Reihe suchen, z.B. anhand des dnp Codes? Beispiel: Ich will alle Artikel aus der Reihe ScharfesC. Unter anderem hat ein Artikel den Code A1109ScharfesC. Wenn ich allerdings nach *ScharfesC suche, findet es nichts.

Hallo Herr Armbruster,

nein, das geht nicht. Sie können aber entweder nach dem Autor suchen. Dann findet er allerdings auch Artikel des Autors, die nicht zu der Reihe gehören. Oder Sie suchen nach „scharfes C“. Dann findet er aller der Reihe. Allerdings auch noch welche, die darauf Bezug nehmen.

Die teilweise überlangen Artikel empfinde ich persönlich nicht als vorteilhaft. Das ist sicherlich Geschmackssache. Allerdings sind auch viele Artikel künstlich durch riesige Einleitungen aufgebläht, was für mein Verständnis für einen Fachartikel nicht immer notwendig ist.

Ich bin mir bewusst, dass v.a. der letzte Punkte diskussionsbedürftig ist. Wie seht ihr das?

Geschäftspraktiken der ppedv AG

Heute möchte ich über ein weniger erfreuliches Thema sprechen: Die Geschäftspraktiken der ppedv AG. Bis 2010 besuchte ich regelmäßig Schulungen in der Karlsruher Zweigstelle. Mein ehemaliger Kollege Steffen K.  und mein aktueller Kollege Samuel Isaac waren ebenfalls bereits Kunde.

Nun verhält es sich seit Monaten so, dass ich vergeblich versuche unsere Kundendaten dort löschen zu lassen, primär um keine unerwünschte Werbung mehr zu erhalten. Im September 2012 verfasste ich folgende E-Mail:

Guten Tag,

inzwischen schreibe ich Ihnen seit einem Jahr regelmäßig, dass ich keine weitere Werbung in irgendeiner Form, ob nun per Post oder Email, wünsche. Nachdem Sie mir mehrmals bestätigt haben, dass ich nun keine weiteren Werbemeldungen erhalte, habe ich soeben wieder den aktuellen Schulungskatalog erhalten.

Deshalb hier von mir sachgemäß formuliert. Sehen Sie es als letzte Warnung:

Sie wurden nun mehrfach aufgefordert Werbemaßnahmen zu unterlassen und jegliche von mir gespeicherte Daten zu löschen. Sollte ich weiterhin von Ihnen in irgendeiner Form angeschrieben werden, sehe ich mich gezwungen rechtliche Schritte einzuleiten. Darüber hinaus gebe ich hiermit als IT-Leiter den Auftrag, alle sonstigen Daten der Firma heco gmbh und deren Mitarbeiter zu löschen. Speziell weiße ich Sie auf Herrn Samuel Isaac (ehemals Esaak) hin, der ebenfalls Schulungen besucht hatte.

 

Darauf erhielt ich eine Antwort in der sinngemäß steht, dass ich angeblich aus dem Verteiler für Werbung gestrichen worden sei, dass aber zur Qualitätssicherung der Adressdaten mind. 1x jährlich jeder Kunde postalisch qualifiziert wird. Nachdem sich keine Besserung einstellte, verfassten ich und mein Kollege im Januar folgende E-Mail, deren Betreff “Letzte Aufforderung” lautet:

Guten Tag,

nach Rücksprache mit unserem Datenschutzbeauftragten und unserem Rechtsanwalt fordere ich Sie hiermit das letzte Mal auf mit postalisch oder in sonstiger Form zu adressieren. Ich weise Sie ausdrücklich gemäß §20 und $6 BDSG darauf hin, dass ich mein hiermit mein Widerspruchsrecht in Anspruch nehme und Sie auffordere meine Daten zu sperren!

Sofern Sie ein weiteres Mal gegen diese Regelung verstoßen, sehen wir uns gezwungen rechtliche Schritte einzuleiten. Herr Isaac wird Sie ebenfalls in gleicher Form benachrichtigen, sodass Sie auch von ihm eine entsprechende Sperr-Aufforderung erhalten. Im Rahmen meiner Funktion als IT Abteilungsleiter widerspreche ich hiermit im Namen unseres Unternehmens jeglicher Kontaktierung!

§20 Berichtigung, Löschung und Sperrung von Daten; Widerspruchsrecht

Siehe hierzu Abs. 3 An die Stelle einer Löschung tritt eine Sperrung, soweit

1. einer Löschung gesetzliche, satzungsmäßige oder vertragliche Aufbewahrungsfristen entgegenstehen,

2. Grund zu der Annahme besteht, dass durch eine Löschung schutzwürdige Interessen des Betroffenen beeinträchtigt würden, oder

3. eine Löschung wegen der besonderen Art der Speicherung nicht oder nur mit unverhältnismäßig hohem Aufwand möglich ist.

§6 Rechte des Betroffenden:

Abs: 1 Die Rechte des Betroffenen auf Auskunft (§§ 19, 34) und auf Berichtigung, Löschung oder Sperrung (§§ 20, 35) können nicht durch Rechtsgeschäft ausgeschlossen oder beschränkt werden.

 

20130314_183818Leider erhielten wir diese Woche wieder Werbung in Form eines Schulungskatalogs. Selbst unser ehemaliger Kollege, der seit Jahren nicht mehr für uns tätig ist, wird weiterhin angeschrieben.

 

 

 

 

 

 

Persönlich halte ich das für keine gesunde Basis für eine Geschäftsbeziehung, sodass ich hoffe, den Kontakt baldmöglichst beenden zu können. Ich vermute darüber hinaus, dass hier rechtliche Verstöße vorliegen. Aus diesem Grund will ich nun einen Anwalt kontaktieren. Doch im Vorhinein suche ich noch nach weiteren Personen, die ebenfalls auf ähnlich fragwürdige Geschäftspraktiken der ppedv AG gestoßen sind. Gerne hier als Kommentar hinterlassen oder mich über Facebook, Twitter oder per E-Mail kontaktieren.

Meine tägliche Portion Git – Remote Branches synchronisieren

Über

   1: git branch -a

kann man sich alle lokalen und remote Branches anzeigen lassen. Den lokalen löscht man über

   1: g branch -D <branch name>

während der Remote Branche über

   1: git push --delete origin <branch name>

entfernt wird.

Nun kann es im letzten Beispiel zu folgendem Fehler kommen:

error: unable to delete ‚branch_name‘: remote ref does not exist

error: failed to push some refs to ‚git@ci:comwork‘

 

Das liegt daran, dass die angezeigt Liste aus dem ersten Beispiel nicht mit dem Server abgeglichen und somit nicht mehr existierende Remote Branches ausgegeben wurden. Der Befehl

   1: git remote prune origin

korrigiert diesen Missstand. Falls also auf dem Server Branches gelöscht wurden, werden diese aus dem lokalen Repository bzw. aus dem Cache ebenfalls entfernt.

Aktuelle NuGet Packages in Build Skripten verwenden

Alex Groß von GROSSWEBER hat uns freundlicherweise eine Ruby Klasse geschrieben, welche es ermöglicht im Build Vorgang immer die aktuellste Version eines NuGet Package heranzuziehen.

Wer beispielsweise MSpec als UnitTesting Framework einsetzt und ein entsprechendes Skript in seinem Build Server verwendet, der hatte das Problem, dass das Skript angepasst werden musste, sobald man MSpec per NuGet aktualisierte. Das gilt natürlich für jegliches Package, auf welches in Skripten direkt referenziert wird.

Um die Problematik nun elegant zu lösen, sei exemplarisch unten folgendes Szenario aufgelistet:

 

Hier zeige ich den Ruby Code, welcher bei uns im Build Skript zur Ausführung der Unit Tests verwendet wird. In Zeile 3 wird die Lösung von Alex verwendet. Erster Parameter gibt den Namen des Package an, während zweiter Parameter besagt wo alle Packages im Repository liegen. Als Rückgabewert erhält man den Pfad zur aktuellsten Version. Im nächsten Schritt in Zeile 4 iteriere ich über unser Binaries Verzeichnis drüber. Dabei werden alle DLLs verarbeitet, die mit ‘comWORK’ beginnen. Als Ausnahme gebe ich alle Dateien an, die auf ‘resources’ enden. Das Ergebnis ist eine Liste von DLLs, welche MSpec dann prüft bzw. ausführt. Die Reports landen im Verzeichnis ‘Reports’ und liegen in Form von html Dateien zur Ansicht bereit.

   1: desc 'Unit Tests'

   2: task :unit do

   3:     mspec = NuGetLatest('Machine.Specifications', 'Source\_Solutions\packages')

   4:     FileList.new('Binaries/**/comWORK.*.dll').exclude('**/*.resources.dll').each do |f|

   5:         Mspec.run({

   6:             :tool => mspec + '/tools/mspec-clr4.exe',

   7:             :reportdirectory => 'Reports',

   8:             :assembly => f

   9:         })

  10:     end

  11: end

 

Hier das von Alex bereitgestellte Ruby File, welches immer das Verzeichnis der aktuellsten Package Version zurückliefert. Anpassungen sind keine nötig.

   1: class NuGetLatest

   2:   attr_reader :path

   3:  

   4:   def initialize(package_name, packages_dir = Dir.pwd)

   5:     @package_name = package_name

   6:  

   7:     raise "#{packages_dir} is not a directory" unless File.directory? packages_dir

   8:  

   9:     Dir.chdir packages_dir do

  10:       candidates = Dir["#{package_name}*"]

  11:       raise "No package '#{package_name}' was found in #{packages_dir}" unless candidates.any?

  12:  

  13:       latest = find_latest_version candidates

  14:       @path = File.join packages_dir, latest

  15:     end

  16:   end

  17:  

  18:   def to_s

  19:     @path

  20:   end

  21:  

  22:   def +(other)

  23:     to_s + other

  24:   end

  25:  

  26:   private

  27:   def find_latest_version(candidates)

  28:     return candidates.first if candidates.length == 1

  29:  

  30:     latest = candidates.map { |path|

  31:       version = path.sub /^#{@package_name}./, ''

  32:       version = parse_version version

  33:  

  34:       {

  35:         :version => version,

  36:         :path => path

  37:       }

  38:     }.max { |left, right| left[:version] <=> right[:version] }

  39:  

  40:     latest[:path]

  41:   end

  42:  

  43:   def parse_version(version_string)

  44:     major, minor, patch, revision, special = version_string.match(/^(\d+)\.(\d+)\.(\d+)\.?(\d+)?-?(.+)?$/).captures

  45:     SemVer.new(major.to_i, minor.to_i, patch.to_i, revision.to_i, special)

  46:   end

  47:  

  48:   # Borrowed from the SemVer gem and enhanced to support .NET's 4-digit versioning system.

  49:   class SemVer

  50:     attr_accessor :major, :minor, :patch, :revision, :special

  51:  

  52:     def initialize(major = 0, minor = 0, patch = 0, revision = 0, special = '')

  53:       major.kind_of? Integer or raise "invalid major: #{major}"

  54:       minor.kind_of? Integer or raise "invalid minor: #{minor}"

  55:       patch.kind_of? Integer or raise "invalid patch: #{patch}"

  56:       revision.kind_of? Integer or raise "invalid revision: #{revision}"

  57:  

  58:       unless special.nil? or special.empty?

  59:         special =~ /[A-Za-z][0-9A-Za-z-]+/ or raise "invalid special: #{special}"

  60:       end

  61:  

  62:       @major, @minor, @patch, @revision, @special = major, minor, patch, revision, special

  63:     end

  64:  

  65:     def <=>(other)

  66:       maj = @major.to_i <=> other.major.to_i

  67:       return maj unless maj == 0

  68:  

  69:       min = @minor.to_i <=> other.minor.to_i

  70:       return min unless min == 0

  71:  

  72:       pat = @patch.to_i <=> other.patch.to_i

  73:       return pat unless pat == 0

  74:  

  75:       rev = @revision.to_i <=> other.revision.to_i

  76:       return rev unless rev == 0

  77:  

  78:       spe = @special <=> other.special

  79:       return spe unless spe == 0

  80:  

  81:       0

  82:     end

  83:  

  84:     include Comparable

  85:   end

  86: end

  87:  

  88: module Conversions

  89:   def NuGetLatest(package_name, packages_dir)

  90:     NuGetLatest.new(package_name, packages_dir)

  91:   end

  92: end

  93:  

  94: include Conversions

 

Hier die MSpec Klasse zum Ausführen der Unit Tests. Vorsicht: Das Skript prüft eine Umgebungsvariable und ist dediziert auf uns zugeschnitten (Einsatz von Team City). Hier müsstet ihr also Anpassungen vornehmen.

//Update: Wie ich inzwischen erfahren habe, macht MSpec die Prüfung auf die von Team City gesetzte Umgebungsvariable inzwischen implizit!

   1: class Mspec

   2:   def self.run(attributes)

   3:     tool = attributes.fetch(:tool)

   4:     reportDirectory = attributes.fetch(:reportdirectory, '.').to_absolute

   5:     assembly = attributes.fetch(:assembly).to_absolute

   6:     

   7:     reportFile = assembly.name.ext('html').in(reportDirectory).to_absolute

   8:     FileUtils.mkdir_p reportFile.dirname

   9:     

  10:     mspec = tool.to_absolute

  11:     

  12:     Dir.chdir(assembly.dirname) do

  13:       sh "#{mspec.escape} #{'--teamcity ' if ENV['TEAMCITY_PROJECT_NAME']}--timeinfo --html #{reportFile.escape} #{assembly.escape}"

  14:     end

  15:   end

  16: end

Meine tägliche Portion Git – Tags

Wer vor der Aufgabe steht alle bestehenden Tags aus Git zu löschen, kann dies wie folgt bewerkstelligen:

   1: git tag | xargs git push --delete origin

   2: git tag | xargs git tag -d

Über “git tag” holt man sich alle vorhandenen Tags, welche durch ‚”|” an den nächsten Befehl weitergereicht (Pipe) werden. “xargs” besagt, dass die übergebenen Werte per Schleife durchlaufen und ans Ende des Befehls angefügt werden. Somit werden zunächst alle Remote Tags gelöscht (Zeile 1) und im Anschluss alle lokalen Tags (Zeile 2). Mit

   1: git tag

kann mich sich zur Verifizierung nochmals alle Tags ausgeben lassen. Das Ergebnis sah bei mir im Testszenario dann so aus:

image

%d Bloggern gefällt das: