Подтвердить что ты не робот

Как указать, что объекты DateTime, полученные из EntityFramework, должны быть DateTimeKind.UTC

У меня есть программа на С#, где все объекты DateTime DateTimeKind.UTC. При сохранении объектов в базе данных он сохраняет UTC, как ожидалось. Однако при их возврате они DateTimeKind.Unspecified. Есть ли способ сообщить Entity Framework (Code First) при создании объектов DateTime на С#, чтобы всегда использовать DateTimeKind.UTC?

4b9b3361

Ответ 1

Нет, нет. И это на самом деле DateTimeKind.Unspecified.

Однако, если вас беспокоит поддержка нескольких часовых поясов, вы должны рассмотреть возможность использования DateTimeOffset. Он похож на обычный DateTime, за исключением того, что он не представляет собой "перспективу" времени, он представляет собой абсолютное представление, в котором 3PM (UTC-3) равно 4PM (UTC-2). DateTimeOffset содержит как DateTime, так и часовой пояс и поддерживается как EntityFramework, так и SQL Server.

Ответ 2

У вас может быть, что ваш datacontext фиксирует все соответствующие значения по мере их появления. Следующее делает это с кешем свойств для типов сущностей, чтобы избежать необходимости каждый раз проверять тип:

public class YourContext : DbContext
{
  private static readonly List<PropertyInfo> EmptyPropsList = new List<PropertyInfo>();
  private static readonly Hashtable PropsCache = new Hashtable(); // Spec promises safe for single-reader, multiple writer.
                                                                  // Spec for Dictionary makes no such promise, and while
                                                                  // it should be okay in this case, play it safe.
  private static List<PropertyInfo> GetDateProperties(Type type)
  {
    List<PropertyInfo> list = new List<PropertyInfo>();
    foreach(PropertyInfo prop in type.GetProperties())
    {
      Type valType = prop.PropertyType;
      if(valType == typeof(DateTime) || valType == typeof(DateTime?))
        list.Add(prop);
    }
    if(list.Count == 0)
      return EmptyPropsList; // Don't waste memory on lots of empty lists.
    list.TrimExcess();
    return list;
  }
  private static void FixDates(object sender, ObjectMaterializedEventArgs evArg)
  {
    object entity = evArg.Entity;
    if(entity != null)
    {
      Type eType = entity.GetType();
      List<PropertyInfo> rules = (List<PropertyInfo>)PropsCache[eType];
      if(rules == null)
        lock(PropsCache)
          PropsCache[eType] = rules = GetPropertyRules(eType); // Don't bother double-checking. Over-write is safe.
      foreach(var rule in rules)
      {
        var info = rule.PropertyInfo;
        object curVal = info.GetValue(entity);
        if(curVal != null)
          info.SetValue(entity, DateTime.SpecifyKind((DateTime)curVal, rule.Kind));
      }
    }
  }
  public YourContext()
  {
    ((IObjectContextAdapter)this).ObjectContext.ObjectMaterialized += FixDates;
    /* rest of constructor logic here */
  }
  /* rest of context class here */
}

Это также можно объединить с атрибутами, чтобы позволить устанавливать DateTimeKind каждое свойство должно иметь, сохраняя набор правил о каждом свойстве, а не только PropertyInfo, и ищет атрибут в GetDateProperties.

Ответ 3

Мое решение, сначала используя код: Объявите свойства DateTime следующим образом:

private DateTime _DateTimeProperty;
public DateTime DateTimeProperty
{
    get
    {
        return _DateTimeProperty;
    }
    set
    {
        _DateTimeProperty = value.ToKindUtc();
    }
}

Также можно создать свойство как:

private DateTime? _DateTimeProperty;
public DateTime? DateTimeProperty
{
    get
    {
        return _DateTimeProperty;
    }
    set
    {
        _DateTimeProperty = value.ToKindUtc();
    }
}

ToKindUtc() является расширением для изменения DateTimeKind.Unspecified до DateTimeKind.Utc или вызова ToUniversalTime(), если kind DateTimeKind.Local Здесь код для расширений:

public static class DateTimeExtensions
{
    public static DateTime ToKindUtc(this DateTime value)
    {
        return KindUtc(value);
    }
    public static DateTime? ToKindUtc(this DateTime? value)
    {
        return KindUtc(value);
    }
    public static DateTime ToKindLocal(this DateTime value)
    {
        return KindLocal(value);
    }
    public static DateTime? ToKindLocal(this DateTime? value)
    {
        return KindLocal(value);
    }
    public static DateTime SpecifyKind(this DateTime value, DateTimeKind kind)
    {
        if (value.Kind != kind)
        {
            return DateTime.SpecifyKind(value, kind);
        }
        return value;
    }
    public static DateTime? SpecifyKind(this DateTime? value, DateTimeKind kind)
    {
        if (value.HasValue)
        {
            return DateTime.SpecifyKind(value.Value, kind);
        }
        return value;
    }
    public static DateTime KindUtc(DateTime value)
    {
        if (value.Kind == DateTimeKind.Unspecified)
        {
            return DateTime.SpecifyKind(value, DateTimeKind.Utc);
        }
        else if (value.Kind == DateTimeKind.Local)
        {
            return value.ToUniversalTime();
        }
        return value;
    }
    public static DateTime? KindUtc(DateTime? value)
    {
        if (value.HasValue)
        {
            return KindUtc(value.Value);
        }
        return value;
    }
    public static DateTime KindLocal(DateTime value)
    {
        if (value.Kind == DateTimeKind.Unspecified)
        {
            return DateTime.SpecifyKind(value, DateTimeKind.Local);
        }
        else if (value.Kind == DateTimeKind.Utc)
        {
            return value.ToLocalTime();
        }
        return value;
    }
    public static DateTime? KindLocal(DateTime? value)
    {
        if (value.HasValue)
        {
            return KindLocal(value.Value);
        }
        return value;
    }
}

Не забудьте включить в файл модели.

using TheNameSpaceWhereClassIsDeclared;

Метод set свойства вызывается при чтении из базы данных с EF или при назначении в методе редактирования контроллера MVC.

Предупреждение. Если в веб-формах, если вы редактируете даты в локальном часовом поясе, вы ДОЛЖНЫ преобразовать дату в UTC перед отправкой на сервер.

Ответ 4

Посмотрите на ответ michael.aird здесь: fooobar.com/info/87236/... Он маркирует дату UTC во время загрузки, с событием ObjectMaterialized.