简体   繁体   English

实体框架,代码优先和日期时间

[英]Entity framework, code first and datetimes

So, I have a very large project with heavy DI's in place. 因此,我有一个非常庞大的项目,其中包含大量的DI。 The solution is overly architected and very complex. 该解决方案的架构过于复杂,非常复杂。 The solution was developed using EF Code first approach (no model exists) and with most of the table objects, it contains one or more DateTime properties. 该解决方案是使用EF Code first方法(不存在模型)开发的,并且对于大多数表对象,它包含一个或多个DateTime属性。

It has come (way late in the process!) to the point where I need to convert the datetimes into UTC format. 它已经到了(过程很晚!),我需要将日期时间转换为UTC格式。 For existing data in the DB, I can run a SQL Script and do a conversion easily as a one time job. 对于数据库中的现有数据,我可以运行SQL脚本并轻松完成一次转换工作。

But for the future and running code, what is the best way to convert (at the time of the insert, update and select) from the UTC format TO and FROM the DB and apply an offset (ie -2 hours) to show to the UI the correct datetime? 但是对于将来和正在运行的代码,从UTC格式TO和FROM DB转换(插入,更新和选择时)并应用偏移量(即-2小时)以显示给UTC的最佳方法是什么? UI正确的日期时间? (ie UTC to PST) (即UTC到PST)

One thing to bare in mind is that there is ALOT of code, ALOT of nested and deep down buried code and I want to be able to find the easiest way, without touching all the objects, interfaces etc... to convert it all to UTC at time of issuing the SQL command within EF. 要记住的一件事是,有很多代码,很多嵌套的和深层的埋藏代码,我希望能够找到最简单的方法,而无需触摸所有对象,接口等...即可将其全部转换为在EF中发出SQL命令时的UTC。 I want to use the SQL Server methods to convert to UTC when storing and convert from UTC when retrieving rather than within the .NET level. 我想使用SQL Server方法在存储时转换为UTC,而在检索而不是在.NET级别时从UTC转换。

Any thoughts or insights would be much appreciated. 任何想法或见解将不胜感激。

There is no code to show here as this isn't a real coding issue but rather more of an insight discussion on how to get EF to execute (when it constructs the query before calling SQL) SQL Server functions for converting to and from UTC and returning back the result set with the correct datetime. 没有代码可在此处显示,因为这不是一个真正的编码问题,而是更多有关如何使EF执行(在调用SQL之前构造查询时)如何进行往返于UTC和返回具有正确日期时间的结果集。

Thank you. 谢谢。

You can override the EF SaveChanges() method to check if any of the modified entities have a date and convert that to the UTC date. 您可以重写EF SaveChanges()方法来检查是否有任何修改的实体具有日期,并将其转换为UTC日期。 Here is an example code to put in your DB context. 这是放置在数据库上下文中的示例代码。

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();
}

So this will check if any of the modified/added entities has a property called Date and set that to a UTC date. 因此,这将检查是否有任何修改/添加的实体具有名为Date的属性,并将其设置为UTC日期。 This may not be what you need but this is the way you should approach the solution to have one place to convert the dates to UTC. 这可能不是您所需要的,但这是您应采用的解决方案,以便有一个将日期转换为UTC的地方。

A few things: 一些东西:

  • Yes, your database should store UTC, and yes, the you can convert to a specific time zone before displaying in the UI. 是的,您的数据库应存储UTC,是的,您可以将其转换为特定时区,然后再显示在UI中。 However, the data access layer is not the correct place to do this. 但是,数据访问层不是执行此操作的正确位置。 The data model should accurately reflect what's in the database. 数据模型应准确反映数据库中的内容。

    If you are just converting timestamps for input or display, then the best practice is to do this as early as possible on the way in, and as late as possible on the way out. 如果您只是将时间戳转换为输入或显示,则最佳做法是在进场时尽早进行此操作,并在出路时尽早进行此操作。 For some this means that the conversion is done in a controller or view model, and for others it's pushed all the way down to the client and done in JavaScript. 在某些情况下,这意味着转换是在控制器或视图模型中完成的,而在另一些情况下,则一直将其下推到客户端并使用JavaScript完成。 Where to do it is entirely up to you, but in the data access layer is usually not appropriate for that. 在哪里做完全取决于您,但是在数据访问层通常不适合这样做。

  • Sometimes (but not always) it makes sense to do the conversion in your domain layer , especially if the domain involves decisions made based on a local date or time. 有时(但并非总是如此)在您的域层中进行转换是有意义的,尤其是当域涉及基于本地日期或时间做出的决策时。 It's helpful if your domain can accurately model time in different time zones. 如果您的域可以准确地模拟不同时区的时间,这将很有帮助。 Noda Time is is really good for that, as it contains dedicated types such as Instant , LocalDate , and ZonedDateTime . Noda Time确实非常有用,因为它包含专用类型,例如InstantLocalDateZonedDateTime

  • Your desire to do this in one place such that you don't have to touch all the parts of your code is understandable - but I can tell you from experience that taking a one-size-fits-all approach is eventually going to come back to haunt you. 您希望在一处执行此操作,而不必触摸代码的所有部分,这是可以理解的-但我可以从经验中告诉您,采用“一刀切”的方法最终会回来困扰你 The fact is, the common advice of "always use UTC" is shortsighted. 事实是,“始终使用UTC”的常见建议是短视的。 Eventually you will have scenarios that need a local time value. 最终,您将遇到需要本地时间值的情况。 Not all usage of DateTime is for the same purpose. 并非所有使用DateTime的目的都是相同的。 Often UTC is appropriate, but sometimes it is not. UTC通常是适当的,但有时不合适。 If you find a way to apply UTC conversions globally in your architecture, you are giving up the ability to control that. 如果您找到一种在体系结构中全局应用UTC转换的方法,那么您将放弃对此进行控制的能力。

    In particular, timestamping is a good scenario for UTC (or DateTimeOffset ), but scheduling is not. 特别是, 时间戳记对于UTC(或DateTimeOffset )是一个很好的方案,但调度不是。 Schedules are usually based on a local time, such as an alarm clock that goes off at 8:00 every morning (in the implied local time), or a meeting that occurs every Wednesday at 10:00 AM Eastern time. 日程安排通常基于当地时间,例如闹钟每天早上8:00(在暗示的当地时间)关闭,或者在东部时间每周三的10:00 AM召开会议。

    Also, consider that some date-time scenarios really are just about a fixed date without a time. 另外,请考虑某些日期时间方案实际上只是一个没有时间的固定日期。 Birthdates and work anniversaries are a good example of that. 生日和工作周年纪念就是一个很好的例子。 Don't try to convert those things to UTC, or you may end up being +/- 1 day. 请勿尝试将这些内容转换为UTC,否则最终可能会+/- 1天。

  • Also, you said you are trying to convert to a fixed offset, but you also said you wanted to convert from UTC to PST. 另外,您说过您正在尝试转换为固定偏移量,但是您也说过要从UTC转换为PST。 You should understand that PST is only in effect for part of the year. 您应该了解PST仅在一年的一部分时间内生效。 When daylight saving time is in effect, Pacific time switches to PDT. 当夏令时生效时,太平洋时间切换到PDT。 To convert time zones correctly, you can't just use a fixed offset. 要正确转换时区,您不能仅使用固定的偏移量。 The conversion needs to decide whether -08:00 or -07:00 is appropriate for the timestamp being converted. 转换需要确定-08:00或-07:00是否适合要转换的时间戳。 See also "Time Zone != Offset" in the timezone tag wiki . 另请参见时区标签Wiki “时区!=偏移”。

Hope that helps, and good luck with your project! 希望对您有所帮助,并祝您项目顺利!

Since EF 6 you can use an Interceptor and modify the DbCommand before it hits the DB. 从EF 6开始,您可以使用拦截器并在DbCommand到达数据库之前对其进行修改。 https://msdn.microsoft.com/en-us/data/dn469464(v=vs.113).aspx#BuildingBlocks https://msdn.microsoft.com/zh-cn/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
            }
        }
} 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM