Keine Indices für nvarchar(MAX)

Heute habe ich an einer SQL-Datenbank, die ich via Entity Framework 4 von einer C#-Anwendung aus anspreche, „von Hand“ Kolonnen hinzugefügt, um Änderungen an meinen Entities nachzuvollziehen, ohne die Daten in den Tabellen zu verlieren. Dabei ist mir zum ersten mal richtig aufgefallen, dass alle meine textuellen Kolonnen vom Typ nvarchar(MAX) sind, bzw. dass EF4 die Kolonnen so für mich definiert hat.

MAX schien mir Overkill, aber richtig, ich hatte ja bei den Properties im EF-Designer keine Maximal-Längen-Angaben gemacht. Irgendwie verständlich, weil man schliesslich beim O/R-Mapping vom C#-Datentyp String her kommt, wo man sich keine Gedanken über Maximallängen machen muss.

Zur Sicherheit klärte ich ab, ob ich mir mit der Verwendung von nvarchar(MAX) irgendwelche Nachteile einhandle. Ich dachte da an eine mögliche Speicherverschwendung, die so zustandekommt. Eine Frage auf Stack Overflow brachte Klärung: Nein, Speicherverschwendung ist kein Problem, aber SQL Server mag keine normalen Indices bauen mit MAX-Kolonnen drin.

Es ist tatsächlich ein bisschen schwierig, einen B-Baum zu führen mit potentiell beliebig langen Schlüsseln in Seiten fixer Länge!

Neugierig geworden, forschte ich noch etwas weiter. Maximallängen setzen bei den Properties im EF4-Designer löst zwar das erwähnte Indizier-Problem, hat aber eine Schwäche: EF4 selbst überwacht die Maximallängen nicht, sondern gibt einfach alles an den SQL Server weiter, wo es dann zwar schon einen Fehler gibt, aber offenbar einen, bei dem man unter Umständen nicht versteht, wo das Problem liegt. Diese Geschichte ist hier näher beschrieben.

Weiterhin scheint es überraschend schwierig zu sein, die Maximallängen-Angaben, die man im Designer macht, zur Programmlaufzeit abzufragen, z.B. um irgendwelche Eingabe-Controls dynamisch und „generisch“ auf die betreffenden Längen einzuschränken. Nachlesen kann man das z.B. hier.

Schliesslich scheint es mit Code First in EF4.1 und/oder bei Einsatz von SQL Server Compact eine Reihe neuer Fragen rund um die Maximallänge von Text-Kolonnnen zu geben, wie man hier beschrieben findet.

Es ist schon interessant, wie sich beim Programmieren mit .NET immer mal wieder Dinge als vielschichtiger herausstellen, als man auf den ersten Blick annimmt.

Veröffentlicht in Allgemein. Schlagwörter: , . Leave a Comment »

EF4: Zu meckern gibt es immer etwas

Im Rahmen meiner bisherigen Arbeit mit dem EF4 bin ich auf ein paar Dinge gestossen, welche dieses Framework nicht kann, die aber wünschenswert und sinnvoll wären. Ich führe diese hier auf, weil es eine nützliche Information sein kann zu wissen, dass etwas nicht geht – man kann dann nämlich aufhören nach einer direkten Lösung zu suchen und sein Ansinnen entweder fallenlassen oder damit beginnen, eine Umgehungslösung zu suchen.

Weil sich solche Dinge heutzutage schnell ändern können: Die folgenden Aussagen beziehen sich auf das Entity Framework 4, so wie in Visual Studio 2010 (original d.h. ohne Service Pack 1) enthalten.

  • Es gibt im Datenbank-Designer für das EF4 keine Möglichkeit, die Reihenfolge von Properties zu ändern, weder mit der Maus interaktiv (etwa via „Drag & Drop“) noch durch Änderungen im Eigenschaften-Fenster. Umgehungslösung: Direkt im XML hinter dem Designer herumpfuschen, so wie z.B. hier erläutert.
  • Arbeitet man Design First d.h. generiert die Datenbank ab Design, gibt es keine Möglichkeit, sich im Designer zu Indices zu äussern: Indices kennt dieser schlicht nicht, abgesehen von denjenigen für Primary Keys natürlich.
  • Ebensowenig kennt der Designer Unique Constraints.
  • EF4 unterstützt Enumerations nicht. Leute lassen sich hier alle möglichen Umgehungslösungen einfallen, wie z.B. diese hier, aber das grundsätzliche Problem schleckt keine Geiss weg, wie man hier in der Schweiz zu sagen pflegt. Etwas pikant ist an dieser Geschichte noch, dass LINQ to SQL offenbar Enumerations unterstützt.

Bei allen 4 aufgeführten Dingen erstaunt es mich etwas, dass man mit dem Entity Framework Release 4 erreicht, ohne eine Lösung anzubieten. Wenn man die Signale von Microsoft richtig deutet, ist ja das EF zumindest im Moment die favorisierte Datenbank-Zugriffs-Technologie für .NET-Programme und hätte darum Detail-Pflege sicher verdient.

Veröffentlicht in Allgemein. Schlagwörter: . Leave a Comment »

ASP.NET, EF4 und Threads: Klappt das eigentlich?

Seit einiger Zeit arbeitete ich mich in die Welt der Programmierung von Web-Applikationen ein, mit Hilfe von ASP.NET MVC2, unter Verwendung von Entity Framework 4 (EF4) für den Datenbank-Zugriff.

Es ging eine ganze Weile, bis mir auffiel, dass in allem Demo-Code und in allen Demo-Projekten wie etwa dem Nerd Dinner nirgends die Rede war von Datenkonsistenz-Problemen, die es geben kann bei Verwendung von ASP.NET und EF4. ASP.NET arbeitet per se mit Multi-Threading, und deshalb können die Datenbankzugriffe ganz schön durcheinandergehen, wenn man auf einem Web-Server eine anständige Menge an Zugriffen hat. Zudem bringt die Verwendung von EF4 mit sich, dass in einem ObjectContext-Objekt eine Menge Daten zwischengespeichert werden können. Die Gefahr, dass sich mehrere Nutzer meiner Web-Applikation gegenseitig ihre Änderungen überschreiben, schien mir real zu sein.

Heute bin ich deshalb dieser Frage auf den Grund gegangen und dabei auf eine kleine Überraschung gestossen.

Multi-Threading in ASP.NET findet statt auf der Ebene der Requests: 1 Request wird jeweils in einem eigenen Thread ausgeführt. In ASP.NET MVC2 werden Controllers pro Request jeweils neu erzeugt; wenn man also wie in den Samples vorgegeben einen EF4-Objekt-Kontext als normale Property der Controller-Klasse implementiert, leben diese Objekte nur recht kurz, womit sich auch das Risiko von Konflikten deutlich reduziert.

Nebenbei bemerkt: Solange man nicht selbst Threads erzeugt in seiner MVC-Applikation, sondern nur dem „automatischen“ Threading von ASP.NET unterworfen ist, hat man also kein Problem damit, dass ObjectContext wie viele andere Framework-Klassen nicht thread-safe ist. Man darf nur nicht auf die Idee kommen, ein solches Objekt static zu deklarieren in seinem Controller!

Soweit, so gut, aber das Risiko von Konflikten sinkt damit natürlich nicht auf Null.

Die erwähnte Überraschung (zumindest für mich) fand sich schliesslich in diesem MSDN-Artikel: Per Default prüft EF4 bei Datenveränderungen nicht auf irgendwelche Optimismus-Verletzungen, sondern überschreibt einfach munter mit den aktuellen Daten in den Entities.

Mir persönlich scheint das ein etwas fragwürdiger Default zu sein, aber zum Glück kann man ihn relativ einfach überstimmen: Auf der Ebene einzelner Properties in einem EF4-Datenmodell ändert man einfach die Eigenschaft Concurrency Mode weg vom Default None auf Fixed. Die korrekte Behandlung einer OptimisticConcurrencyException, die es dann bei SaveChanges() geben kann, wird z.B. in diesem MSDN-Artikel erläutert. Wieso allerdings dieser Modus „fixed“ heisst, hat sich mir bisher nicht erschlossen…

Wenn’s etwas komplizierter wird und man z.B. einen eigenen Datenzugriffs-Layer in seiner Applikation implentieren will, findet man hier gute Erläuterungen zu Varianten, wie man die „Lebenszeit“ von ObjectContext-Objekten organisieren kann.

Veröffentlicht in Allgemein. Schlagwörter: , , . 1 Comment »