实体框架始终将DateTimeOffset保存为UTC [英] Entity Framework always save DateTimeOffset as UTC

查看:63
本文介绍了实体框架始终将DateTimeOffset保存为UTC的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有一种方法可以指示实体框架始终将DateTimeOffset存储为UTC值.从技术上讲,没有理由这样做,但是如果数据库中的所有数据都一致,我会更喜欢.

Is there a way that I can instruct Entity Framework to always store DateTimeOffset as the UTC value. Technically there is no reason for this but I prefer it if all the data in my database is consistent.

当前,它存储从客户端收到的DateTimeOffset,它可以是取决于用户区域设置的任何内容.

Currently it is storing the DateTimeOffset as received from the client which could be anything depending on the users locale.

我当时正在考虑拦截所有SaveChanges方法,循环进行更改,查找DateTimeOffset类型并显式进行转换,但是如果EntityFramework内置了某些东西,似乎可以减轻很多工作.

I was thinking of perhaps intercepting all the SaveChanges method, looping through the changes, looking for DateTimeOffset types and doing the conversion explicitly, but this seems like a lot of work which could be mitigated if EntityFramework has something built in.

任何见解或建议将不胜感激.

Any insight or suggestions would be greatly appreciated.

编辑:我的帖子和其他与该主题相关的文章的区别在于,我的C#属性的类型为DateTimeOffset,而我的数据库字段也为DateTimeOffset(0).除了一致性之外,没有其他技术原因可以进行转换.如果我将值存储为"17:00 +5:00"或"10:00 -2:00",则没关系,这两个时间点都是相同的.但是,我希望将所有日期存储为"12:00 +0:00",以便在SSMS或其他数据库工具中更易于阅读.

The difference between my post and others dealing with this topic is that my C# property is of type DateTimeOffset and my database field is also DateTimeOffset(0). There is not technical reason to convert other than consistency. If I store a value as "17:00 +5:00" or "10:00 -2:00" it doesn't matter, those are both identical moments in time. However, I would like to have all my dates stored as "12:00 +0:00" so that it is easier to read in SSMS or other DB tools.

看来似乎没有简单"的方法可以实现,所以我现在想解决DbContext.SaveChanges()函数中的问题.问题是,无论我做什么,价值都不会改变?到目前为止,这是代码:

EDIT 2: Seeing as there doesn't seem to be "simple" way to do this I am looking to now tackle the problem in the DbContext.SaveChanges() function. The problem is that no matter what I do, the value won't change? Here's the code so far:

public new void SaveChanges()
{
    foreach (var entry in this.ChangeTracker.Entries())
    {
        foreach (var propertyInfo in entry.Entity.GetType().GetProperties().Where(p => p.CanWrite && p.PropertyType == typeof(DateTimeOffset)))
        {
            var value = entry.CurrentValues.GetValue<DateTimeOffset>(propertyInfo.Name);

            var universalTime = value.ToUniversalTime();
            entry.CurrentValues[propertyInfo.Name] = universalTime;
            // entry.Property(propertyInfo.Name).CurrentValue = universalTime;

            // Adding a watch to "entry.CurrentValues[propertyInfo.Name]" reveals that it has not changed??
        }

        // TODO: DateTimeOffset?
    }

    base.SaveChanges();
}

编辑3 我终于设法解决了这个问题,请参见下面的答案

EDIT 3 I finally managed to solve this, see answer below

推荐答案

感谢我的帮助.由于 Jcl

public new void SaveChanges()
{
    foreach (var entry in this.ChangeTracker.Entries().Where(p => p.State == EntityState.Added || p.State == EntityState.Modified))
        {
        foreach (var propertyInfo in entry.Entity.GetType().GetTypeProperties().Where(p => p.PropertyType == typeof(DateTimeOffset)))
        {
            propertyInfo.SetValue(entry.Entity, entry.CurrentValues.GetValue<DateTimeOffset>(propertyInfo.Name).ToUniversalTime());
        }
        foreach (var propertyInfo in entry.Entity.GetType().GetTypeProperties().Where(p => p.PropertyType == typeof(DateTimeOffset?)))
        {
            var dateTimeOffset = entry.CurrentValues.GetValue<DateTimeOffset?>(propertyInfo.Name);
            if (dateTimeOffset != null) propertyInfo.SetValue(entry.Entity, dateTimeOffset.Value.ToUniversalTime());
        }
    }

     base.SaveChanges();
}

Jcl 的建议下,我写了一个小助手来缓存反射:

At the advice of Jcl, I wrote a small helper to cache the reflection:

public static class TypeReflectionExtension
{
    public static Dictionary<Type, PropertyInfo[]> PropertyInfoCache;

    static TypeReflectionHelper()
    {
        PropertyInfoCache = new Dictionary<Type, PropertyInfo[]>();
    }

    public static PropertyInfo[] GetTypeProperties(this Type type)
    {
        if (!PropertyInfoCache.ContainsKey(type))
        {
            PropertyInfoCache[type] = type.GetProperties();
        }
        return PropertyInfoCache[type];
    }
}

为了简化代码,我创建了一个泛型函数,可用于拦截和修改任何数据类型:

EDIT 2: To clean up the code a bit I created a generic function which you can use to intercept and modify any Data Type:

public static class DbEntityEntryExtension
{
    public static void ModifyTypes<T>(this DbEntityEntry dbEntityEntry, Func<T, T> method)
    {
        foreach (var propertyInfo in dbEntityEntry.Entity.GetType().GetTypeProperties().Where(p => p.PropertyType == typeof(T) && p.CanWrite))
        {
            propertyInfo.SetValue(dbEntityEntry.Entity, method(dbEntityEntry.CurrentValues.GetValue<T>(propertyInfo.Name)));
        }
    }
}

它的用法是(在您的DbContext内部):

The usage of this is (Inside your DbContext):

public new void SaveChanges()
{
    foreach (var entry in this.ChangeTracker.Entries().Where(p => p.State == EntityState.Added || p.State == EntityState.Modified))
    {
        entry.ModifyTypes<DateTimeOffset>(ConvertToUtc);
        entry.ModifyTypes<DateTimeOffset?>(ConvertToUtc);
    }

    base.SaveChanges();
}

private static DateTimeOffset ConvertToUtc(DateTimeOffset dateTimeOffset)
{
    return dateTimeOffset.ToUniversalTime();
}

private static DateTimeOffset? ConvertToUtc(DateTimeOffset? dateTimeOffset)
{
    return dateTimeOffset?.ToUniversalTime();
}

免责声明这确实解决了我的问题,但不建议这样做.我什至不知道是否要使用它,因为现在感觉有点不对了(感谢 Jcl ;).因此,请谨慎使用.最好通过 Adam Benson

Disclaimer This does solve my problem but is not recommended. I don't even know if I am going to use this as something about it just feels wrong now (Thanks Jcl ;). So please do use this with caution. It may probably be better that you follow the answer by Adam Benson

这篇关于实体框架始终将DateTimeOffset保存为UTC的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆