【问题标题】:Can I convert a SQL DataType of DateTime to a DateTimeOffSet in EF?我可以在 EF 中将 DateTime 的 SQL DataType 转换为 DateTimeOffSet 吗?
【发布时间】:2013-10-17 05:12:52
【问题描述】:

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

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

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

我试过这个:

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

但我得到了错误

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

【问题讨论】:

  • @ArsenMrkt - 如果我遵循该线程中接受的答案,我会收到一个新错误:“属性'CreateDate'不是类型'{ObjectType}'的声明属性。验证属性尚未使用 Ignore 方法或 NotMappedAttribute 数据注释从模型中显式排除。请确保它是有效的原始属性。"

标签: c# sql-server entity-framework datetime


【解决方案1】:

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

首先,定义以下属性:

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

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

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 是DateTime,这也可以。因为种类设置为 UTC,所以DateTimeOffset 中的偏移量将设置为零。

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

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

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

【讨论】:

  • 不是完全我想要的,而是朝着正确方向迈出了相当大的一步。
猜你喜欢
  • 2018-06-24
  • 2019-09-02
  • 1970-01-01
  • 1970-01-01
  • 2012-12-05
  • 2011-06-24
  • 2013-07-25
  • 1970-01-01
  • 2011-06-02
相关资源
最近更新 更多