Ich verwende Dapper, um meine Entitäten SQL Server CE zuzuordnen. Wenn ich eine speichern DateTime
mit Kind=Utc
, als ich es las zurück erhalte ich eine DateTime
mit Kind=Unspecified
, die für alle Arten von Problemen führt.
Beispiel:
var f = new Foo { Id = 42, ModificationDate = DateTime.UtcNow };
Console.WriteLine("{0} ({1})", f.ModificationDate, f.ModificationDate.Kind);
connection.Execute("insert into Foo(Id, ModificationDate) values(@Id, @ModificationDate)", f);
var f2 = connection.Query<Foo>("select * from Foo where Id = @Id", f).Single();
Console.WriteLine("{0} ({1})", f2.ModificationDate, f2.ModificationDate.Kind);
Dieser Code gibt folgende Ausgabe:
20/09/2012 10:04:16 (Utc)
20/09/2012 10:04:16 (Unspecified)
Ich weiß, dass ich ein DateTimeOffset
, aber leider hat SQL CE keine Unterstützung für diesen Typ.
Gibt es eine Problemumgehung? Kann ich Dapper sagen, dass alle Daten DateTimeKind.Utc
? Und allgemein, was sind meine Möglichkeiten, das Mapping anzupassen?
BEARBEITEN: Meine aktuelle Problemumgehung besteht darin, die Daten zu patchen, nachdem Dapper das Ergebnis materialisiert hat, aber es riecht irgendwie ...
var results = _connection.Query<Foo>(sql, param).Select(PatchDate);
...
static Foo PatchDate(Foo f)
{
if (f.ModificationDate.Kind == DateTimeKind.Unspecified)
f.ModificationDate = DateTime.SpecifyKind(f.ModificationDate, DateTimeKind.Utc);
return f;
}
Hinzufügen dieser Antwort für alle anderen, die nach einer einfachen Lösung suchen. Dies ist jetzt mit dem Hinzufügen von SqlMapper.TypeHandler in Dapper möglich.
Fügen Sie diese Klasse hinzu, um den Wert aus der db in ein datetime mit der als UTC angegebenen Art zu konvertieren.
public class DateTimeHandler : SqlMapper.TypeHandler<DateTime>
{
public override void SetValue(IDbDataParameter parameter, DateTime value)
{
parameter.Value = value;
}
public override DateTime Parse(object value)
{
return DateTime.SpecifyKind((DateTime)value, DateTimeKind.Utc);
}
}
Dann füge ich in meiner Global.asax-Datei meiner Web-API den Typhandler zu dapper hinzu.
SqlMapper.AddTypeHandler(new DateTimeHandler());
Wenn Sie sicherstellen müssen, dass Sie Daten immer als UTC eingeben, können Sie mit der SetValue-Methode Folgendes verwenden:
parameter.Value = DateTime.SpecifyKind(value, DateTimeKind.Utc);
Blick in den Dapper-Code. Wenn meine Version nicht veraltet ist, führt Dapper für Value-Typen wie datetime (die DbType.DateTime zugeordnet ist) einfach eine einfache Umwandlung aus dem IDataReader-Objekt durch.
Pseudo: Rendite (DateTime) IDataReader.GetValue (0);
Das ist der spezielle Fall für Datetime aus einer Reihe von generischem Code und Lambdas.
AFAIK, SQL datetime speichert niemals den Versatz / die Zeitzone, so dass der Typ bei jedem Speichern und Abrufen von Datum und Uhrzeit immer "Nicht spezifiziert" sagt.
Also, um es sauber zu machen , könntest du adelige Interna berühren:
Das ist ein Problem, da Sie eine große IL-Generierungsmethode (den DataRow Deserializer) berühren und einen if-Fall für DateTime einfügen müssen.
ODER
Setze einfach einen Setter auf die DateTime-Requisiten, wo UTC ein Problem ist (was gegen POCO ist, aber relativ gesund ist):
class Foo
{
private DateTime _modificationDate;
public DateTime ModificationDate
{
get { return _modificationDate; }
set { _modificationDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); }
}
//Ifs optional? since it's always going to be a UTC date, and any DB call will return unspecified anyways
}