3

我有一个大型数据库,我们在其中进行了很多 TimeZone 转换。我正在慢慢地将数据库转换为使用 DateTimeOffSet 数据类型,但这是我无法全面做到的。变化太大。

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

如何让 EF 为我即时进行转换?

我试过这个:

modelBuilder.Properties<DateTimeOffset>()
                .Configure( c => c.HasColumnType( "datetime" ) );

但我得到了错误

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

4

1 回答 1

6

这是您可能会考虑的一种方法:

首先,定义以下属性:

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

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

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

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

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

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

    [DateTimeKind(DateTimeKind.Utc)]
    public DateTime Bar { get; set; }
}

有了这个,每当实体框架从数据库加载一个实体时,它都会设置DateTimeKind你指定的,比如 UTC。

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

DateTimeOffset BarDTO = foo.Bar;

即使foo.Bar是 a DateTime,这也会起作用。因为种类设置为 UTC,所以偏移量将在DateTimeOffset.

当然,你总是可以在你的模型中这样做:

[NotMapped]
public DateTimeOffset BarDTO
{
    get { return Bar; }
    set { Bar = value.UtcDateTime; }
}

我相信您可以根据自己的需要对此进行修改。主要的是,无论属性映射到该字段,类型都必须匹配。

于 2013-10-09T19:53:31.113 回答