我有一个大型数据库,我们会在其中进行大量的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]' 成员'ModifyDate',类型为'CodeFirstDatabaseSchema。{ObjectType}'。
答案 0 :(得分: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));
}
}
}
现在将该属性挂钩到您的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; }
}
有了这个,只要Entity Framework从数据库加载实体,它就会设置你指定的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; }
}
我相信你可以根据自己的需要提出相应的变化。最重要的是,无论属性映射到字段,类型必须匹配。