Toolroom Tech Blog

Devlopers Digest

Enterprise Architect DDL Typen

Falls jemand, so wie ich, eine steinalte Version von Enterprise Architect besitzt, aber neuere Datenbanken modellieren will, kann die Typen entweder selbst anlegen oder bei Sparx Systems runterladen. In Enterprise Architect unter "Tools" auf "Import Reference Data", die jeweilige Datei suchen, in der Liste auswählen und importieren ... und verwenden.

Hier die "Save as ..." Links direkt zu den Downloads:

SQL Server 2005

SQL Server 2008

Informix

MS Access 2007

SQLite

oder direkt bei Sparx unter "Data Modeling Types" herunterladen.

datetime vs. datetime2 im Entity Framework

Nimm datetime2

Ich bin bei der Arbeit mit dem EntityFramework 4 und SQL Server 2008 gerade wieder über eine erstmal seltsam klingende Fehlermeldung gerattert:

System.Data.SqlClient.SqlException : The conversion of a datetime2 
data type to a datetime data type resulted in an out-of-range value.

Die Erklärung dafür ist relativ einfach: Der Datentyp datetime ist in manchen Dingen etwas limitiert. Beispielsweise ist es den Meisten wohl schon mal passiert, dass er den 01.01.0001 zumindest unbeabsichtigt in die Datenbank schreiben wollte. Microsoft hat daher eine Art Erweiterung des datetime Datentyps eingeführt ... der heisst datetime2 und verspricht einiges besser zu können als sein Vorfahr, indem er bessere Genauigkeit und eine größere Zeitspanne von 01.01.0001 bis 31.12.9999 einführt.

Und fein ist dabei, dass wir DateTime.Min jetzt auch in die Datenbank schicken können.

var min = DateTime.Min;
var max = DateTime.Max;

//min is equivalent to 00:00:00.0000000, January 1, 0001 
//max is 23:59:59.9999999, December 31, 9999, exactly one 100-nanosecond tick before 00:00:00, January 1, 10000

Mehr dazu gibt es auf TechNet und TechNet2.

Das Entity Framework verwendet vermutlich auch deswegen seit Version 4 datetime2 statt datetime. Wer nun aber mit der oben genannten SqlException kämpft aber die bestehende Datenbank nicht anpassen kann/will, kann im XML seines Entity Data Model files (*.edmx) das ProviderManifestToken von 2008 auf 2005 ändern, und schon wird wieder mit der alten Zeit (also datetime) gearbeitet.

<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="2.0" xmlns:edmx="http://schemas.microsoft.com/ado/2008/10/edmx">
  <!-- EF Runtime content -->
  <edmx:Runtime>
    <!-- SSDL content -->
    <edmx:StorageModels>
    <Schema Namespace="DBModel.Store" ProviderManifestToken="2005" Alias="Self" Provider="System.Data.SqlClient">
        <EntityContainer Name="DBModelStoreContainer">

So, ich muss jetzt wieder zurück in die Zukunft...

Dreiecke mit CSS

Dieses versteckte CSS-Feature erfreut sich immer größerer Beliebtheit: Dreiecke zeichnen. Und das Beste daran ist, dass man lediglich die Border property dazu braucht.

Beginnen wir mal mit den Basics, einem quadratischen Container mit einem dicken, fetten, bunten Rahmen.

<div class="bordered"></div> 
.bordered{
 height: 10px;
 width: 10px;
 background-color:lightgreen;
 border-color: red yellow green blue;
 border-style: solid;
 border-width: 10px 10px 10px 10px;
}

Man kann schon sehr gut erkennen, dass der Browser den Stoß der aneinandertreffenden Kanten abschrägt. Als nächstes setzen wir die Maße des Containers auf 0.

 

.arrow-all{
 height: 0px;
 width: 0px;
 border-color: red yellow green blue;
 border-style: solid;
 border-width: 10px 10px 10px 10px;
}

Wie zu erwarten war, sehen wir nun nur noch den Rahmen, der wiederum nur aus Dreiecken besteht. Nun machen wir 3 davon noch transparent und fertig ist der Pfeil.

 

.arrow{ height: 0px; width: 0px;}
.arrow-n
{
 border-color: transparent transparent green transparent;
 border-style: solid;
 border-width: 0px 10px 10px 10px;
}

Und den Pfeil nun in die rechte untere Ecke zeigen zu lassen, nehmen wir diesen Nord-Pfeil und halbieren ihn, indem wir einfach den rechten Rand auf 0 setzen.

.arrow{ height: 0px; width: 0px;}
.arrow-se{
 border-color: transparent transparent green transparent;
 border-style: solid;
 border-width: 0px 0px 14.14px 14.14px;
}

Und damit kann man sich jetzt beliebig spielen.

Viel Spaß!

 

Eigene Applikation mit Url starten

click://me

Ein Kunde hat angefragt, ob es möglich wäre, eine Feature in seine (von mir entwickelte :)) Windows-Unternehmenslösung einzubauen, mit der er Links zu Inhalten aus der Applikation per Mail verschicken kann. So wie bei Skype: Try it here! 

Natürlich geht das!

Und so geht's

Gehen wir davon aus, dass wir mit der Url myapp://user/m.muster das Benutzerprofil des Benutzers m.muster in unserer Applikation, deren ausführbare Datei unter C:\Programme\MyApplication\myapplication.exe zu finden ist, öffnen wollen. Dazu sind nur wenige Schritte notwendig:

1) Protokoll registrieren

Zuerst muss Windows das eigene Protokoll mitgeteilt werden, indem folgende Registry Keys angelegt werden:

[HKEY_CLASSES_ROOT\myapp]
@="URL:My Application Protocol"
"URL Protocol"=""

[HKEY_CLASSES_ROOT\myapp\shell]

[HKEY_CLASSES_ROOT\myapp\shell\open]

[HKEY_CLASSES_ROOT\myapp\shell\open\command]
@="\"C:\\Programme\\MyApplication\\myapplication.exe\" \"%1\""

Man kann das dann natürlich auch schön im Setup machen :)

Zu beachten ist dabei, dass der Key unter HKEY_CLASSES_ROOT der Protokollname ist (also myapp://). Der Pfad in der letzten Zeile zeigt auf die aufzurufende Datei, und %1 ist der Platzhalter für die aufgerufene Url.

2) Die Applikation vorbereiten

Jetzt muss man der App noch beibringen, mit dem Parameter umzugehen. Grundsätzlich muss man dazu lediglich die Url aus den StartupEventArgs holen und intern auswerten.

In meinem Fall ging das alles sehr schnell, da ich dank MVVM und meiner generischen Genialität (bin ich dann generial?) nur ein paar Aufrufe zu erledigen hatte. Ich schreibe die Parameter ausserdem in eine Queue, die erst dann abgearbeitet wird, sobald das MainWindow initialisiert ist, dann gibts auch keine seltsamen Fehlermeldungen. 

protected override void OnStartup(StartupEventArgs e)
{
    if (e.Args.Length > 0)
        ParamQueue.Enqueue(e.Args[0]);
}

private static void HandleUrlParameter(string url)
{
    if(!Current.Dispatcher.CheckAccess())
    {
        Current.Dispatcher.BeginInvoke(new HandleUrlParameterDelegate(HandleUrlParameter), url);
        return;
    }

    if(!url.StartsWith(string.Format("{0}://", UrlProtocol.ProtocolKey)))
    {
        return;
    }

    url = url.Replace(string.Format("{0}://", UrlProtocol.ProtocolKey), "");

    var data = url.Replace(string.Format("{0}://", UrlProtocol.ProtocolKey), "");
    var parts = data.Split(new []{"/"}, StringSplitOptions.RemoveEmptyEntries);

    try
    {
        switch (parts.Length)
        {
            case 1:
                if (parts[0] == "user") { LoadListView<UserListViewModel, User>(); return;}
                if (parts[0] == "customer") { LoadListView<CustomerListViewModel, Customer>(); return; }
                break;
            case 2:
                if (parts[0] == "user") { LoadEditForm(typeof(UserViewModel), typeof(User), new User { Id = Convert.ToInt64(parts[1]) }); return; }
                if (parts[0] == "customer") { LoadEditForm(typeof(CustomerViewModel), typeof(Customer), new Customer { Id = Convert.ToInt64(parts[1]) }); return; }
                break;
        }
    }
    catch (Exception ex)
    {
                
    }

    MessageBox.Show("Invalid Link");
}

 In diesem Beispiel wird zur Vereinfachung bei jedem Aufruf eine neue Instanz der Applikation gestartet. Um bestehende Instanzen zu verwenden, muss man dann noch die Verwendung einer SingleInstance implementieren. Aber das ist eine andere Geschichte ...