2016-03-01 197 views
0

所以,我有一个非常大的项目与沉重的DI的地方。该解决方案架构过于复杂,非常复杂。 该解决方案是使用EF Code第一种方法开发的(不存在模型)以及大多数表格对象,它包含一个或多个DateTime属性。实体框架,代码优先和datetimes

它已经到了(过程中晚了!)到我需要将日期时间转换为UTC格式的点。对于数据库中的现有数据,我可以运行SQL脚本并轻松完成一次转换。

但是对于将来和运行的代码,什么是从UTC格式转换(在插入,更新和选择时)TO和FROM数据库并应用偏移量(即-2小时)的最佳方法是什么?向用户界面展示正确的日期时间? (即UTC到PST)

有一点需要记住的是,有很多代码,ALOT嵌套和深层隐藏代码,我希望能够找到最简单的方法,而不用触及所有对象,接口等......在EF内发出SQL命令时将其全部转换为UTC。我希望在存储时使用SQL Server方法转换为UTC,并在检索时从UTC转换而不是在.NET级别内转换。

任何想法或见解将不胜感激。

没有代码在这里显示,因为这不是一个真正的编码问题,而是更多关于如何获得EF执行(当它在调用SQL之前构造查询时)的深入讨论SQL Server函数for转换为UTC和从UTC转换并返回具有正确日期时间的结果集。

谢谢。

+1

不要紧多少代码有 - 避免mixups的唯一方法是使用正确的类型:'datetimeoffset'数据库和'DateTimeOffset'为.NET。此外,UTC的含义是什么?有或没有夏令时?至于时区*名称*,三字缩写词不是标准的。唯一的“标准”是包含在像NodaTime这样的图书馆中的IANA数据库。 PS PS。 –

+0

PS。这*是一个与EF无关的编码问题。正如无法避免错误,如果您使用ASCII而不是Unicode,那么如果使用'datetime'而不是'datetimeoffset',则无法避免错误。即使这样也不能阻止时区规则发生变化时的问题,就像他们在俄罗斯所做的那样 - 在过去的十年里至少有三次。如果您的域名需要它,您可能必须将IANA tz名称存储在单独的列中,例如“俄罗斯/莫斯科”以避免规则更改问题 –

+1

如果您使用UTC捕捉时间,则在堆栈中从UI本地日期/时间)尽可能早到UTC,并尽可能晚地从UTC转换为特定地点的日期/时间。你的问题不是一个非常具体的问题,它的解释是开放的,而且更多的是基于观点的。我会[使用谷歌](https://www.google.com/search?q=storing%20utc%20c%23&rct=j),而不是做更多的研究,你不会得到这个线程好/尖的答案。一旦你对如何处理它有了更好的想法,并有尖锐的问题回来问他们。 – Igor

回答

0

您可以重写EF SaveChanges()方法来检查是否有任何修改的实体有日期并将其转换为UTC日期。以下是放置在数据库上下文中的示例代码。

public override int SaveChanges() 
{ 
    var selectedEntityList = ChangeTracker.Entries() 
          .Where(x => x.Entity is EntityInformation && 
          (x.State == EntityState.Added || x.State == EntityState.Modified)); 

    foreach (var entity in selectedEntityList) 
    { 

     ((EntityInformation)entity.Entity).Date = TimeZoneInfo.ConvertTimeToUtc(DateTime.Now.ToUniversalTime()); 
    } 

    return base.SaveChanges(); 
} 

因此,这将检查是否有任何修改/添加的实体有一个属性叫做日期,并设置为UTC日期。这可能不是您所需要的,但这是您应该通过解决方案将某个位置转换为UTC的方式。

+0

感谢詹姆斯,而不是必须在C#代码中完成它,我想通过SQL生成的代码(EF做)代替它...... –

+0

@Ahmedilyas此方法将修改EF生成的SQL代码正在重写EF上SaveChanges的基本方法。 –

+0

不知道你要在这里展示什么,但'TimeZoneInfo.ConvertTimeToUtc(DateTime.Now.ToUniversalTime())'是写'DateTime.UtcNow'的更复杂的方法。 –

0

有几件事情:

  • 是的,你的数据库应该存储UTC,是的,你将可以在用户界面中显示之前转换为特定的时区。但是,数据访问层是而不是这是正确的位置。数据模型应该准确地反映数据库中的内容。

    如果您只是将时间戳转换为输入或显示,那么最好的做法是尽可能早地在进行中以及在出路时尽可能晚地执行此操作。对于某些情况,这意味着转换是在控制器或视图模型中完成的,对于其他人来说,它一直推到客户端,并在JavaScript中完成。在哪里做到这一点完全取决于你,但在数据访问层通常不适合。

  • 有时(但并非总是),在您的域层中进行转换是有意义的,尤其是在域涉及基于本地日期或时间的决策时。如果您的网域可以在不同时区准确建模时间,这会很有帮助。Noda Time对此非常有用,因为它包含专用类型,例如InstantLocalDateZonedDateTime

  • 您希望在一个地方做到这一点,以便您不必触摸代码的所有部分都是可以理解的 - 但我可以从经验告诉你,采取一刀切的方法是最终会回来困扰你。事实是,“总是使用UTC”的常见建议是短视的。最终你会有需要本地时间值的场景。并非DateTime的所有用法都用于同一目的。通常UTC是合适的,但有时并非如此。如果您找到了在体系结构中全局应用UTC转换的方法,那么您就放弃了控制它的能力。

    尤其时间戳是UTC(或DateTimeOffset)一个很好的方案,但调度是没有的。时间表通常基于当地时间,例如闹钟在每天早晨8点(隐含的当地时间)停止,或者每周三东部时间上午10点发生的会议。

    此外,请考虑一些日期时间方案确实只是一个没有时间的固定日期。生日和工作纪念日就是一个很好的例子。不要试图将这些东西转换为UTC,否则最终可能会变为+/- 1天。另外,你说你试图转换到一个固定的偏移量,但你也表示你想从UTC转换到PST。您应该了解,PST仅在一年的部分时间内生效。夏令时生效时,太平洋时间切换到PDT。要正确转换时区,您不能只使用固定偏移量。转换需要确定-08:00或-07:00是否适合正在转换的时间戳。另请参阅the timezone tag wiki中的“时区!=偏移”。

希望对你的项目有所帮助,祝你好运!

+0

谢谢!我同意你的观点,不应该在数据库层完成,但不幸的是EF模型在包括UI在内的任何地方使用......没有VM的概念,当它们存在时,他们首先使用EF模型代码: –

+0

这是一个桌面应用程序?还是ASP.NET MVC?其他? –

+0

它应该不重要:)但它是一个ASP.NET MVC应用程序。 –

0

由于EF 6可以使用拦截器并在命中数据库之前修改DbCommand。 https://msdn.microsoft.com/en-us/data/dn469464(v=vs.113).aspx#BuildingBlocks

public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) 
{ 
    for (int i = 0; i < command.Parameters.Count; i++) { 
      var param = command.Parameters[i]; 
      if (param.DbType == DbType.DateTime) { 
       // Change param.Value here 
      } 
     } 
}