我可以将DateTime的SQL数据类型转换为EF中的DateTimeOffSet吗?

Rus*_*uss 3 c# sql-server datetime entity-framework

我有一个大型数据库,我们在那里进行了大量的TimeZone转换.我正在慢慢地将数据库转换为使用DateTimeOffSet数据类型,但这是我无法做到的事情.变化太大了.

但是我可以更改代码,因为我知道我的所有日​​期都以UTC格式存储在数据库中,所以我想在.NET中使用DateTimeOffSet对象.

我怎样才能让EF为我实时转换?

我试过这个:

modelBuilder.Properties<DateTimeOffset>()
                .Configure( c => c.HasColumnType( "datetime" ) );
Run Code Online (Sandbox Code Playgroud)

但是我收到了错误

(37,12):错误2019:指定的成员映射无效.类型'{ObjectType}'中成员'ModifyDate'的类型'Edm.DateTimeOffset [Nullable = True,DefaultValue =,Precision =]'与'SqlServer.datetime [Nullable = True,DefaultValue =,Precision = 3]不兼容'of CodeFirstDatabaseSchema.{ObjectType}'中的成员'ModifyDate'.

Mat*_*int 5

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

首先,定义以下属性:

[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.

现在,你说你想开始切换到DateTimeOffset类型.您可以利用DateTime具有单向隐式转换的事实DateTimeOffset,并将其.Kind考虑在内.换句话说,你可以这样做:

DateTimeOffset BarDTO = foo.Bar;
Run Code Online (Sandbox Code Playgroud)

即使foo.Bar是a DateTime,这也行.由于种类设置为UTC,因此偏移量将设置为零DateTimeOffset.

当然,您可以在模型中使用以下内容执行此操作:

[NotMapped]
public DateTimeOffset BarDTO
{
    get { return Bar; }
    set { Bar = value.UtcDateTime; }
}
Run Code Online (Sandbox Code Playgroud)

我相信你可以根据自己的需要提出相应的变化.主要的是无论属性映射到字段,类型必须匹配.