实体框架DateTime和UTC

Fio*_*onn 87 c# datetime entity-framework utc code-first

是否有可能拥有实体框架(我目前使用的是Code First Approach with CTP5)将所有DateTime值存储为数据库中的UTC?

或者是否有一种方法可以在映射中指定它,例如在last_login列的这一个中:

modelBuilder.Entity<User>().Property(x => x.Id).HasColumnName("id");
modelBuilder.Entity<User>().Property(x => x.IsAdmin).HasColumnName("admin");
modelBuilder.Entity<User>().Property(x => x.IsEnabled).HasColumnName("enabled");
modelBuilder.Entity<User>().Property(x => x.PasswordHash).HasColumnName("password_hash");
modelBuilder.Entity<User>().Property(x => x.LastLogin).HasColumnName("last_login");
Run Code Online (Sandbox Code Playgroud)

Mat*_*int 136

您可以考虑以下一种方法:

首先,定义以下属性:

[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));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在将该属性挂钩到您的EF上下文:

public class MyContext : DbContext
{
    public DbSet<Foo> Foos { get; set; }

    public MyContext()
    {
        ((IObjectContextAdapter)this).ObjectContext.ObjectMaterialized +=
            (sender, e) => DateTimeKindAttribute.Apply(e.Entity);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,在任何DateTimeDateTime?属性上,您都可以应用此属性:

public class Foo
{
    public int Id { get; set; }

    [DateTimeKind(DateTimeKind.Utc)]
    public DateTime Bar { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

有了这个,每当Entity Framework从数据库加载实体时,它将设置DateTimeKind您指定的实体,例如UTC.

请注意,保存时这不会执行任何操作.在尝试保存之前,您仍需要将值正确转换为UTC.但它确实允许您在检索时设置类型,允许将其序列化为UTC,或者将其转换为其他时区TimeZoneInfo.

  • 如果你不能使这个工作,你可能会错过其中一个使用:使用系统; 使用System.Collections.Generic; 使用System.ComponentModel.DataAnnotations.Schema; 使用System.Linq; 使用System.Reflection; (7认同)
  • @Saustrup - 你会发现SO上的大多数例子都会省略用于简洁的用法,除非它们与问题直接相关.但是谢谢. (7认同)
  • 正如@SilverSideDown所说,这只适用于.NET 4.5.我已经创建了一些扩展,使其与.NET 4.0兼容,网址为https://gist.github.com/munr/3544bd7fab6615290561.另外需要注意的是,这不适用于投影,只有完全加载的实体. (7认同)
  • 关于通过预测实现这一目标的任何建议? (5认同)
  • @MattJohnson没有@ Saustrup的使用语句,你会得到一些无用的编译错误,例如`'System.Array'不包含'Where'的定义 (4认同)
  • 请注意,访问"IObjectContextAdapter.ObjectContext"会触发极其昂贵的代码.我正在使用这个解决方案分析一个应用程序,400次调用创建一个DbContext需要超过6秒的活动线程时间:不是很轻量级. (2认同)

Hon*_*fus 33

对于EF Core,在 GitHub 上有一个关于这个主题的很好的讨论:https : //github.com/dotnet/efcore/issues/4711

一种解决方案(归功于Christopher Haws)将导致在将所有日期存储到数据库/从数据库中检索它们时将它们作为 UTC 进行处理的OnModelCreating方法是将以下内容添加到您的DbContext类的方法中:

var dateTimeConverter = new ValueConverter<DateTime, DateTime>(
    v => v.ToUniversalTime(),
    v => DateTime.SpecifyKind(v, DateTimeKind.Utc));

var nullableDateTimeConverter = new ValueConverter<DateTime?, DateTime?>(
    v => v.HasValue ? v.Value.ToUniversalTime() : v,
    v => v.HasValue ? DateTime.SpecifyKind(v.Value, DateTimeKind.Utc) : v);

foreach (var entityType in builder.Model.GetEntityTypes())
{
    if (entityType.IsKeyless)
    {
        continue;
    }

    foreach (var property in entityType.GetProperties())
    {
        if (property.ClrType == typeof(DateTime))
        {
            property.SetValueConverter(dateTimeConverter);
        }
        else if (property.ClrType == typeof(DateTime?))
        {
            property.SetValueConverter(nullableDateTimeConverter);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

此外,如果您想排除某些实体的某些属性被视为 UTC ,请检查此链接

  • `IsQueryType` 似乎已被 `IsKeyLess` 取代:https://github.com/dotnet/efcore/commit/542529a022a2260ba94e60bd40fbe319850b8887#diff-eae0d2afe75e5d194f87e0d620d40c3c (8认同)
  • 为什么需要检查“IsQueryType”(或现在的“IsKeyLess”)? (2认同)

Bob*_*lth 29

我非常喜欢Matt Johnson的方法,但在我的模型中,我的所有DateTime成员都是UTC,我不想用属性来装饰所有这些成员.因此,我概括了Matt的方法,允许事件处理程序应用默认的Kind值,除非使用该属性显式修饰成员.

ApplicationDbContext类的构造函数包含以下代码:

/// <summary> Constructor: Initializes a new ApplicationDbContext instance. </summary>
public ApplicationDbContext()
        : base(MyApp.ConnectionString, throwIfV1Schema: false)
{
    // Set the Kind property on DateTime variables retrieved from the database
    ((IObjectContextAdapter)this).ObjectContext.ObjectMaterialized +=
      (sender, e) => DateTimeKindAttribute.Apply(e.Entity, DateTimeKind.Utc);
}
Run Code Online (Sandbox Code Playgroud)

DateTimeKindAttribute 看起来像这样:

/// <summary> Sets the DateTime.Kind value on DateTime and DateTime? members retrieved by Entity Framework. Sets Kind to DateTimeKind.Utc by default. </summary>
[AttributeUsage(AttributeTargets.Property)]
public class DateTimeKindAttribute : Attribute
{
    /// <summary> The DateTime.Kind value to set into the returned value. </summary>
    public readonly DateTimeKind Kind;

    /// <summary> Specifies the DateTime.Kind value to set on the returned DateTime value. </summary>
    /// <param name="kind"> The DateTime.Kind value to set on the returned DateTime value. </param>
    public DateTimeKindAttribute(DateTimeKind kind)
    {
        Kind = kind;
    }

    /// <summary> Event handler to connect to the ObjectContext.ObjectMaterialized event. </summary>
    /// <param name="entity"> The entity (POCO class) being materialized. </param>
    /// <param name="defaultKind"> [Optional] The Kind property to set on all DateTime objects by default. </param>
    public static void Apply(object entity, DateTimeKind? defaultKind = null)
    {
        if (entity == null) return;

        // Get the PropertyInfos for all of the DateTime and DateTime? properties on the entity
        var properties = entity.GetType().GetProperties()
            .Where(x => x.PropertyType == typeof(DateTime) || x.PropertyType == typeof(DateTime?));

        // For each DateTime or DateTime? property on the entity...
        foreach (var propInfo in properties) {
            // Initialization
            var kind = defaultKind;

            // Get the kind value from the [DateTimekind] attribute if it's present
            var kindAttr = propInfo.GetCustomAttribute<DateTimeKindAttribute>();
            if (kindAttr != null) kind = kindAttr.Kind;

            // Set the Kind property
            if (kind != null) {
                var dt = (propInfo.PropertyType == typeof(DateTime?))
                    ? (DateTime?)propInfo.GetValue(entity)
                    : (DateTime)propInfo.GetValue(entity);

                if (dt != null) propInfo.SetValue(entity, DateTime.SpecifyKind(dt.Value, kind.Value));
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Ham*_*edH 26

在 EF Core 6.0 中添加了 DbContext.ConfigureConventions(),它可以注册特定类型的所有属性的转换。(https://learn.microsoft.com/en-us/ef/core/modeling/bulk-configuration#pre-convention-configuration

这是使用ConfigureConventions的解决方案:

protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
    configurationBuilder
        .Properties<DateTime>()
        .HaveConversion(typeof(UtcValueConverter));
}

class UtcValueConverter : ValueConverter<DateTime, DateTime>
{
    public UtcValueConverter()
        : base(v => v, v => DateTime.SpecifyKind(v, DateTimeKind.Utc))
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

由https://github.com/dotnet/efcore/issues/4711#issuecomment-1048572602提供

  • 完美运作!小而简单。将该代码放入 DBContext 中或创建 DBContext 的部分类,以防您像我一样使用脚手架。 (2认同)
  • 这在 EF 7 中不起作用。ConvertToProviderExpression 是第一个参数,convertFromProviderExpression 是第二个参数。因此,我必须将参数切换为基数才能使其正常工作。基(v =&gt; DateTime.SpecifyKind(v,DateTimeKind.Utc),v =&gt; v) (2认同)

Dan*_*ker 10

Another year, another solution! This is for EF Core.

I have a lot of DATETIME2(7) columns that map to DateTime, and always store UTC. I don't want to store an offset because if my code is correct then the offset will always be zero.

Meanwhile I have other colums that store basic date-time values of unknown offset (provided by users), so they are just stored/displayed "as is", and not compared with anything.

Therefore I need a solution that I can apply to specific columns.

定义扩展方法UsesUtc

private static DateTime FromCodeToData(DateTime fromCode, string name)
    => fromCode.Kind == DateTimeKind.Utc ? fromCode : throw new InvalidOperationException($"Column {name} only accepts UTC date-time values");

private static DateTime FromDataToCode(DateTime fromData) 
    => fromData.Kind == DateTimeKind.Unspecified ? DateTime.SpecifyKind(fromData, DateTimeKind.Utc) : fromData.ToUniversalTime();

public static PropertyBuilder<DateTime?> UsesUtc(this PropertyBuilder<DateTime?> property)
{
    var name = property.Metadata.Name;
    return property.HasConversion<DateTime?>(
        fromCode => fromCode != null ? FromCodeToData(fromCode.Value, name) : default,
        fromData => fromData != null ? FromDataToCode(fromData.Value) : default
    );
}

public static PropertyBuilder<DateTime> UsesUtc(this PropertyBuilder<DateTime> property)
{
    var name = property.Metadata.Name;
    return property.HasConversion(fromCode => FromCodeToData(fromCode, name), fromData => FromDataToCode(fromData));
}
Run Code Online (Sandbox Code Playgroud)

然后可以将其用于模型设置中的属性:

modelBuilder.Entity<CustomerProcessingJob>().Property(x => x.Started).UsesUtc();
Run Code Online (Sandbox Code Playgroud)

与属性相比,它有一个较小的优势,即您只能将其应用于正确类型的属性。

请注意,它假定来自 DB 的值采用 UTC 格式,但只是有错误的Kind. 因此,它会管理您尝试存储在数据库中的值,如果它们不是 UTC,则会引发描述性异常。

  • 这是一个很好的解决方案,应该更高,尤其是现在大多数新开发都将使用 Core 或 .NET 5。 UTC 执行政策的假想加分 - 如果更多人将日期一直保留到实际用户显示的 UTC,我们几乎不会有任何日期/时间错误。 (2认同)

小智 9

这个答案适用于Entity Framework 6

接受的答案不适用于Projected或Anonymous对象.性能也可能是一个问题.

为此,我们需要使用DbCommandInterceptorEntityFramework提供的对象.

创建拦截器:

public class UtcInterceptor : DbCommandInterceptor
{
    public override void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {
        base.ReaderExecuted(command, interceptionContext);

        if (interceptionContext?.Result != null && !(interceptionContext.Result is UtcDbDataReader))
        {
            interceptionContext.Result = new UtcDbDataReader(interceptionContext.Result);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

interceptionContext.Result 是DbDataReader,我们用它们代替

public class UtcDbDataReader : DbDataReader
{
    private readonly DbDataReader source;

    public UtcDbDataReader(DbDataReader source)
    {
        this.source = source;
    }

    public override DateTime GetDateTime(int ordinal)
    {
        return DateTime.SpecifyKind(source.GetDateTime(ordinal), DateTimeKind.Utc);
    }        

    // you need to fill all overrides. Just call the same method on source in all cases

    public new void Dispose()
    {
        source.Dispose();
    }

    public new IDataReader GetData(int ordinal)
    {
        return source.GetData(ordinal);
    }
}
Run Code Online (Sandbox Code Playgroud)

在你的注册中注册拦截器 DbConfiguration

internal class MyDbConfiguration : DbConfiguration
{
    protected internal MyDbConfiguration ()
    {           
        AddInterceptor(new UtcInterceptor());
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,注册您的配置 DbContext

[DbConfigurationType(typeof(MyDbConfiguration ))]
internal class MyDbContext : DbContext
{
    // ...
}
Run Code Online (Sandbox Code Playgroud)

而已.干杯.

为简单起见,这里是DbReader的整个实现:

using System;
using System.Collections;
using System.Data;
using System.Data.Common;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace MyNameSpace
{
    /// <inheritdoc />
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1010:CollectionsShouldImplementGenericInterface")]
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
    public class UtcDbDataReader : DbDataReader
    {
        private readonly DbDataReader source;

        public UtcDbDataReader(DbDataReader source)
        {
            this.source = source;
        }

        /// <inheritdoc />
        public override int VisibleFieldCount => source.VisibleFieldCount;

        /// <inheritdoc />
        public override int Depth => source.Depth;

        /// <inheritdoc />
        public override int FieldCount => source.FieldCount;

        /// <inheritdoc />
        public override bool HasRows => source.HasRows;

        /// <inheritdoc />
        public override bool IsClosed => source.IsClosed;

        /// <inheritdoc />
        public override int RecordsAffected => source.RecordsAffected;

        /// <inheritdoc />
        public override object this[string name] => source[name];

        /// <inheritdoc />
        public override object this[int ordinal] => source[ordinal];

        /// <inheritdoc />
        public override bool GetBoolean(int ordinal)
        {
            return source.GetBoolean(ordinal);
        }

        /// <inheritdoc />
        public override byte GetByte(int ordinal)
        {
            return source.GetByte(ordinal);
        }

        /// <inheritdoc />
        public override long GetBytes(int ordinal, long dataOffset, byte[] buffer, int bufferOffset, int length)
        {
            return source.GetBytes(ordinal, dataOffset, buffer, bufferOffset, length);
        }

        /// <inheritdoc />
        public override char GetChar(int ordinal)
        {
            return source.GetChar(ordinal);
        }

        /// <inheritdoc />
        public override long GetChars(int ordinal, long dataOffset, char[] buffer, int bufferOffset, int length)
        {
            return source.GetChars(ordinal, dataOffset, buffer, bufferOffset, length);
        }

        /// <inheritdoc />
        public override string GetDataTypeName(int ordinal)
        {
            return source.GetDataTypeName(ordinal);
        }

        /// <summary>
        /// Returns datetime with Utc kind
        /// </summary>
        public override DateTime GetDateTime(int ordinal)
        {
            return DateTime.SpecifyKind(source.GetDateTime(ordinal), DateTimeKind.Utc);
        }

        /// <inheritdoc />
        public override decimal GetDecimal(int ordinal)
        {
            return source.GetDecimal(ordinal);
        }

        /// <inheritdoc />
        public override double GetDouble(int ordinal)
        {
            return source.GetDouble(ordinal);
        }

        /// <inheritdoc />
        public override IEnumerator GetEnumerator()
        {
            return source.GetEnumerator();
        }

        /// <inheritdoc />
        public override Type GetFieldType(int ordinal)
        {
            return source.GetFieldType(ordinal);
        }

        /// <inheritdoc />
        public override float GetFloat(int ordinal)
        {
            return source.GetFloat(ordinal);
        }

        /// <inheritdoc />
        public override Guid GetGuid(int ordinal)
        {
            return source.GetGuid(ordinal);
        }

        /// <inheritdoc />
        public override short GetInt16(int ordinal)
        {
            return source.GetInt16(ordinal);
        }

        /// <inheritdoc />
        public override int GetInt32(int ordinal)
        {
            return source.GetInt32(ordinal);
        }

        /// <inheritdoc />
        public override long GetInt64(int ordinal)
        {
            return source.GetInt64(ordinal);
        }

        /// <inheritdoc />
        public override string GetName(int ordinal)
        {
            return source.GetName(ordinal);
        }

        /// <inheritdoc />
        public override int GetOrdinal(string name)
        {
            return source.GetOrdinal(name);
        }

        /// <inheritdoc />
        public override string GetString(int ordinal)
        {
            return source.GetString(ordinal);
        }

        /// <inheritdoc />
        public override object GetValue(int ordinal)
        {
            return source.GetValue(ordinal);
        }

        /// <inheritdoc />
        public override int GetValues(object[] values)
        {
            return source.GetValues(values);
        }

        /// <inheritdoc />
        public override bool IsDBNull(int ordinal)
        {
            return source.IsDBNull(ordinal);
        }

        /// <inheritdoc />
        public override bool NextResult()
        {
            return source.NextResult();
        }

        /// <inheritdoc />
        public override bool Read()
        {
            return source.Read();
        }

        /// <inheritdoc />
        public override void Close()
        {
            source.Close();
        }

        /// <inheritdoc />
        public override T GetFieldValue<T>(int ordinal)
        {
            return source.GetFieldValue<T>(ordinal);
        }

        /// <inheritdoc />
        public override Task<T> GetFieldValueAsync<T>(int ordinal, CancellationToken cancellationToken)
        {
            return source.GetFieldValueAsync<T>(ordinal, cancellationToken);
        }

        /// <inheritdoc />
        public override Type GetProviderSpecificFieldType(int ordinal)
        {
            return source.GetProviderSpecificFieldType(ordinal);
        }

        /// <inheritdoc />
        public override object GetProviderSpecificValue(int ordinal)
        {
            return source.GetProviderSpecificValue(ordinal);
        }

        /// <inheritdoc />
        public override int GetProviderSpecificValues(object[] values)
        {
            return source.GetProviderSpecificValues(values);
        }

        /// <inheritdoc />
        public override DataTable GetSchemaTable()
        {
            return source.GetSchemaTable();
        }

        /// <inheritdoc />
        public override Stream GetStream(int ordinal)
        {
            return source.GetStream(ordinal);
        }

        /// <inheritdoc />
        public override TextReader GetTextReader(int ordinal)
        {
            return source.GetTextReader(ordinal);
        }

        /// <inheritdoc />
        public override Task<bool> IsDBNullAsync(int ordinal, CancellationToken cancellationToken)
        {
            return source.IsDBNullAsync(ordinal, cancellationToken);
        }

        /// <inheritdoc />
        public override Task<bool> ReadAsync(CancellationToken cancellationToken)
        {
            return source.ReadAsync(cancellationToken);
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly")]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1816:CallGCSuppressFinalizeCorrectly")]
        public new void Dispose()
        {
            source.Dispose();
        }

        public new IDataReader GetData(int ordinal)
        {
            return source.GetData(ordinal);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 此代码可能应该归功于@IvanStoev:/sf/answers/2824433601/ (2认同)

Mou*_*ono 8

我相信我找到了一个不需要任何自定义UTC检查或DateTime操作的解决方案.

基本上,您需要更改EF实体以使用DateTimeOffset(NOT DateTime)数据类型.这将在数​​据库中存储带有日期值的时区(在我的情况下为SQL Server 2015).

当EF Core从数据库请求数据时,它也会收到时区信息.当您将此数据传递给Web应用程序(在我的情况下为Angular2)时,日期会自动转换为浏览器的本地时区,这正是我所期望的.

当它被传递回我的服务器时,它会自动再次转换为UTC,同样如预期的那样.

  • 与常见的感知相反,DateTimeOffset不存储时区.它存储值表示的UTC偏移量.无法反向映射偏移量以确定创建偏移量的实际时区,从而使数据类型几乎无用. (5认同)
  • 不,但它可以用于正确存储日期时间:https://medium.com/@ojb500/in-praise-of-datetimeoffset-e0711f991cba (2认同)
  • 只有 UTC 不需要位置,因为它到处都是一样的。如果您使用 UTC 以外的其他时间,您还需要位置,否则时间信息是无用的,在使用 datetimeoffset 时也是如此。 (2认同)
  • DATETIMEOFFSET 将执行原始发布者想要的操作:将日期时间存储为 UTC,而无需执行任何(显式)转换。@Carl DATETIME、DATETIME2 和 DATETIMEOFFSET 都正确存储日期时间值。除了额外存储相对于 UTC 的偏移量之外,DATETIMEOFFSET 几乎没有任何优势。您在数据库中使用的内容由您决定。我只是想强调一点,即“它不存储时区”,正如许多人错误地认为的那样。 (2认同)
  • @Suncat2000 优点是您可以按原样将该日期从您的 api 发送到您的客户端浏览器。当客户端浏览器打开此日期时,它知道距 UCT 的偏移量,因此能够将其转换为客户端正在查看的系统上的默认日期。因此,从服务器时区到浏览器时区的转换发生时,开发人员无需为其编写任何代码。 (2认同)

Ogg*_*las 7

感谢@ajcvickers。从 EF Core 2.1 开始,这将是处理 DateTime.Kind 的一种方法:

modelBuilder
    .Entity<Foo>()
    .Property(e => e.SomeDate)
    .HasConversion(v => v, v => DateTime.SpecifyKind(v, DateTimeKind.Utc));
Run Code Online (Sandbox Code Playgroud)

这将确保每次从数据库读取日期时都会自动将其指定为 Utc。

来源:

https://github.com/dotnet/efcore/issues/4711#issuecomment-358695190


小智 6

我现在正在研究这个问题,而且大多数答案都不是很好.从我所看到的,没有办法告诉EF6数据库的日期是UTC格式.如果是这种情况,确保模型的DateTime属性是UTC的最简单方法是在setter中验证和转换.

这里有一些c#like pseudocode描述了算法

public DateTime MyUtcDateTime 
{    
    get 
    {        
        return _myUtcDateTime;        
    }
    set
    {   
        if(value.Kind == DateTimeKind.Utc)      
            _myUtcDateTime = value;            
        else if (value.Kind == DateTimeKind.Local)         
            _myUtcDateTime = value.ToUniversalTime();
        else 
            _myUtcDateTime = DateTime.SpecifyKind(value, DateTimeKind.Utc);        
    }    
}
Run Code Online (Sandbox Code Playgroud)

前两个分支是显而易见的.最后一个拿着秘密酱.

当EF6根据从数据库加载的数据创建模型时,DateTimes是DateTimeKind.Unspecified.如果您知道您的日期在数据库中都是UTC,那么最后一个分支将非常适合您.

DateTime.Now总是DateTimeKind.Local如此,因此上述算法适用于代码中生成的日期.大多数时候.

但是,您必须谨慎,因为还有其他方法DateTimeKind.Unspecified可以潜入您的代码.例如,您可以从JSON数据反序列化模型,并且您的反序列化程序风格默认为此类.这取决于你要防止标记为DateTimeKind.Unknown从除了EF之外的任何人获得该设置者的本地化日期.

  • 正如我在与此问题摔跤数年后发现的那样,如果您将DateTime字段分配或选择到其他结构中,例如数据传输对象,则EF会忽略getter和setter方法.在这些情况下,您仍然必须在生成结果后将Kind更改为"DateTimeKind.Utc".示例:`from my in myContext.Records select new DTO(){BrokenTimestamp = o.BbTimestamp};`将所有Kind设置为`DateTimeKind.Unspecified`. (4认同)
  • 我已经在实体框架中使用 DateTimeOffset 一段时间了,如果您使用 DateTimeOffset 数据类型指定 EF 实体,那么所有 EF 查询都将返回具有 UTC 偏移量的日期,就像保存在数据库中一样。因此,如果您将数据类型更改为 DateTimeOffset 而不是 DateTime,则不需要上述解决方法。 (2认同)

Vij*_*jay 5

无法在实体框架中指定 DataTimeKind。您可以决定在存储到 db 之前将日期时间值转换为 utc,并始终假定从 db 检索的数据为 UTC。但是在查询期间具体化的 DateTime 对象将始终为“未指定”。您还可以使用 DateTimeOffset 对象而不是 DateTime 进行评估。