Hier ist ein Ansatz, den Sie in Betracht ziehen könnten:
Definieren Sie zunächst das folgende Attribut:
[AttributeUsage(AttributeTargets.Property)]
public class DateTimeKindAttribute : Attribute
{
private readonly DateTimeKind _kind;
public DateTimeKindAttribute(DateTimeKind kind)
{
_kind = kind;
}
public DateTimeKind Kind
{
get { return _kind; }
}
public static void Apply(object entity)
{
if (entity == null)
return;
var properties = entity.GetType().GetProperties()
.Where(x => x.PropertyType == typeof(DateTime) || x.PropertyType == typeof(DateTime?));
foreach (var property in properties)
{
var attr = property.GetCustomAttribute<DateTimeKindAttribute>();
if (attr == null)
continue;
var dt = property.PropertyType == typeof(DateTime?)
? (DateTime?) property.GetValue(entity)
: (DateTime) property.GetValue(entity);
if (dt == null)
continue;
property.SetValue(entity, DateTime.SpecifyKind(dt.Value, attr.Kind));
}
}
}
Verbinden Sie nun dieses Attribut mit Ihrem EF-Kontext:
public class MyContext : DbContext
{
public DbSet<Foo> Foos { get; set; }
public MyContext()
{
((IObjectContextAdapter)this).ObjectContext.ObjectMaterialized +=
(sender, e) => DateTimeKindAttribute.Apply(e.Entity);
}
}
Jetzt können Sie dieses Attribut auf eine DateTime
oder DateTime?
mehrere Eigenschaften anwenden:
public class Foo
{
public int Id { get; set; }
[DateTimeKind(DateTimeKind.Utc)]
public DateTime Bar { get; set; }
}
Wenn Entity Framework eine Entität aus der Datenbank lädt, wird die von DateTimeKind
Ihnen angegebene Entität festgelegt , z. B. UTC.
Beachten Sie, dass dies beim Speichern nichts bewirkt. Sie müssen den Wert noch ordnungsgemäß in UTC konvertieren, bevor Sie versuchen, ihn zu speichern. Sie können jedoch die Art beim Abrufen festlegen, sodass sie als UTC serialisiert oder mit in andere Zeitzonen konvertiert werden kann TimeZoneInfo
.
'System.Array' does not contain a definition for 'Where'
Ich mag den Ansatz von Matt Johnson sehr, aber in meinem Modell sind ALLE meine DateTime-Mitglieder UTC und ich möchte nicht alle mit einem Attribut dekorieren müssen. Daher habe ich Matts Ansatz verallgemeinert, damit der Ereignishandler einen Standardwert für Kind anwenden kann, es sei denn, ein Mitglied ist explizit mit dem Attribut versehen.
Der Konstruktor für die ApplicationDbContext-Klasse enthält diesen Code:
DateTimeKindAttribute
sieht aus wie das:quelle
DateTIme
Attribut ohne (öffentliche) Setter-Methode hat. Bearbeiten vorgeschlagen. Siehe auch stackoverflow.com/a/3762475/2279059Die akzeptierte Antwort funktioniert nicht für projizierte oder anonyme Objekte. Leistung könnte auch ein Problem sein.
Um dies zu erreichen, müssen wir
DbCommandInterceptor
ein von EntityFramework bereitgestelltes Objekt verwenden.Interceptor erstellen:
interceptionContext.Result
ist DbDataReader, den wir durch unseren ersetzenRegistrieren Sie den Abfangjäger in Ihrem
DbConfiguration
Registrieren Sie abschließend die Konfiguration für auf Ihrem
DbContext
Das ist es. Prost.
Hier ist der Einfachheit halber die gesamte Implementierung von DbReader:
quelle
Dispose
undGetData
?Ich glaube, ich habe eine Lösung gefunden, die keine benutzerdefinierte UTC-Überprüfung oder DateTime-Manipulation erfordert.
Grundsätzlich müssen Sie Ihre EF-Entitäten ändern, um den Datentyp DateTimeOffset (NOT DateTime) zu verwenden. Dadurch wird die Zeitzone mit dem Datumswert in der Datenbank gespeichert (in meinem Fall SQL Server 2015).
Wenn EF Core die Daten von der Datenbank anfordert, erhält es auch die Zeitzoneninformationen. Wenn Sie diese Daten an eine Webanwendung übergeben (in meinem Fall Angular2), wird das Datum automatisch in die lokale Zeitzone des Browsers konvertiert, was ich erwarte.
Und wenn es an meinen Server zurückgegeben wird, wird es automatisch wieder in UTC konvertiert, auch wie erwartet.
quelle
Es gibt keine Möglichkeit, DataTimeKind im Entity Framework anzugeben. Sie können die Datums- und Uhrzeitwerte vor dem Speichern in db in utc konvertieren und immer davon ausgehen, dass die von db abgerufenen Daten als UTC abgerufen wurden. Die während der Abfrage materalisierten DateTime-Objekte sind jedoch immer "Nicht angegeben". Sie können das DateTimeOffset-Objekt auch anstelle von DateTime bewerten.
quelle
Ich recherchiere gerade darüber und die meisten dieser Antworten sind nicht gerade großartig. Soweit ich sehen kann, kann EF6 nicht mitgeteilt werden, dass die aus der Datenbank stammenden Daten im UTC-Format vorliegen. In diesem Fall können Sie am einfachsten sicherstellen, dass die DateTime-Eigenschaften Ihres Modells in UTC vorliegen, indem Sie den Setter überprüfen und konvertieren.
Hier ist ein c # -ähnlicher Pseudocode, der den Algorithmus beschreibt
Die ersten beiden Zweige liegen auf der Hand. Der letzte enthält die geheime Sauce.
Wenn EF6 ein Modell aus Daten erstellt, die aus der Datenbank geladen wurden, sind DateTimes
DateTimeKind.Unspecified
. Wenn Sie wissen, dass Ihre Daten alle UTC in der Datenbank sind, funktioniert der letzte Zweig hervorragend für Sie.DateTime.Now
ist immerDateTimeKind.Local
, daher funktioniert der obige Algorithmus gut für im Code generierte Daten. Meistens.Sie müssen jedoch vorsichtig sein, da es andere Möglichkeiten
DateTimeKind.Unspecified
gibt, sich in Ihren Code einzuschleichen. Beispielsweise können Sie Ihre Modelle aus JSON-Daten deserialisieren, und Ihr Deserializer-Geschmack ist standardmäßig auf diese Art eingestellt. Es liegt an Ihnen, sich vor lokalisierten Daten zu schützen, die markiert sindDateTimeKind.Unspecified
, wenn Sie von jemand anderem als EF zu diesem Setter gelangen.quelle
DateTimeKind.Utc
nachdem Ihre Ergebnisse generiert wurden. Beispiel:from o in myContext.Records select new DTO() { BrokenTimestamp = o.BbTimestamp };
Setzt alle Arten aufDateTimeKind.Unspecified
.Für EF Core gibt es auf GitHub eine großartige Diskussion zu diesem Thema: https://github.com/dotnet/efcore/issues/4711
Eine Lösung (Dank an Christopher Haws ), die dazu führt, dass alle Daten beim Speichern / Abrufen in der Datenbank als UTC behandelt werden, besteht darin, der
OnModelCreating
Methode IhrerDbContext
Klasse Folgendes hinzuzufügen :Auch überprüfen Sie diesen Link , wenn Sie einige Eigenschaften einiger Einrichtungen aus werden als UTC behandelt ausschließen möchten.
quelle
IsQueryType
scheint ersetzt worden zu sein durchIsKeyLess
: github.com/dotnet/efcore/commit/…Wenn Sie beim Festlegen der Werte darauf achten, UTC-Daten ordnungsgemäß einzugeben, und sich nur darum kümmern, dass DateTimeKind beim Abrufen der Entitäten aus der Datenbank ordnungsgemäß festgelegt wird, lesen Sie meine Antwort hier: https://stackoverflow.com/ a / 9386364/279590
quelle
Noch ein Jahr, noch eine Lösung! Dies ist für EF Core.
Ich habe viele
DATETIME2(7)
Spalten,DateTime
die UTC zugeordnet sind, und speichere sie immer. Ich möchte keinen Versatz speichern, da der Versatz immer Null ist, wenn mein Code korrekt ist.In der Zwischenzeit habe ich andere Spalten, in denen grundlegende Datums- / Uhrzeitwerte mit unbekanntem Versatz (von Benutzern bereitgestellt) gespeichert werden, sodass sie nur "wie sie sind" gespeichert / angezeigt und nicht mit irgendetwas verglichen werden.
Daher brauche ich eine Lösung, die ich auf bestimmte Spalten anwenden kann.
Definieren Sie eine Erweiterungsmethode
UsesUtc
:Dies kann dann für Eigenschaften im Modell-Setup verwendet werden:
Es hat den geringen Vorteil gegenüber Attributen, dass Sie es nur auf Eigenschaften des richtigen Typs anwenden können.
Beachten Sie, dass davon ausgegangen wird, dass die Werte aus der Datenbank in UTC vorliegen, aber nur falsch sind
Kind
. Daher werden die Werte überwacht, die Sie in der Datenbank speichern möchten, und es wird eine beschreibende Ausnahme ausgelöst, wenn sie nicht UTC sind.quelle
Für diejenigen, die eine @ MattJohnson-Lösung mit .net Framework 4 wie mir mit Einschränkungen der Reflexionssyntax / -methode erreichen müssen, ist eine geringfügige Änderung erforderlich, wie unten aufgeführt:
quelle
Die Lösung von Matt Johnson-Pint funktioniert, aber wenn alle Ihre DateTimes UTC sein sollen, wäre das Erstellen eines Attributs zu umständlich. So habe ich es vereinfacht:
quelle
Ein anderer Ansatz wäre, eine Schnittstelle mit den datetime-Eigenschaften zu erstellen und diese in den Teilentitätsklassen zu implementieren. Verwenden Sie dann das SavingChanges-Ereignis, um zu überprüfen, ob das Objekt vom Schnittstellentyp ist, und setzen Sie diese Datums- / Uhrzeitwerte auf die gewünschten Werte. Wenn diese an Datumsangaben erstellt / geändert werden, können Sie sie mit diesem Ereignis füllen.
quelle
In meinem Fall hatte ich nur eine Tabelle mit UTC-Daten. Folgendes habe ich getan:
quelle