Можно ли определить свойства DateTime в объектах сущностей типа Kind == DateTimeKind.Utc
, используя файл .edmx или шаблон t4?
По возможности, используя t4, опишите, пожалуйста, как изменить свойство. В настоящее время свойство генерируется как:
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.DateTime Created
{
get
{
return _created;
}
internal set
{
OnCreatedChanging(value);
ReportPropertyChanging("Created");
_created = StructuralObject.SetValidValue(value);
ReportPropertyChanged("Created");
OnCreatedChanged();
}
}
private global::System.DateTime _created;
partial void OnCreatedChanging(global::System.DateTime value);
partial void OnCreatedChanged();
В нашем случае было непрактично всегда указывать DateTimeKind, как указано ранее:
DateTime utcDateTime = DateTime.SpecifyKind(databaseDateTime, DateTimeKind.Utc);
Если вы хотите, чтобы все объекты DateTime, выходящие из базы данных, указывались как UTC, вам нужно добавить файл преобразования T4 и добавить дополнительную логику для всех объектов DateTime и DateLime, допускающих обнуление, чтобы они инициализировались как DateTimeKind.Utc
У меня есть пост в блоге, который объясняет этот шаг за шагом: http://www.aaroncoleman.net/post/2011/06/16/Forcing-Entity-Framework-to-mark-DateTime-fields-at-UTC.aspx
Короче:
1) Создайте файл .tt для вашей модели .edmx
2) Откройте файл .tt и найдите метод «WritePrimitiveTypeProperty».
3) Заменить существующий установочный код. Это все, что находится между ReportPropertyChanging
ReportPropertyChanged
метода ReportPropertyChanging
и ReportPropertyChanged
со следующим:
<#+ if( ((PrimitiveType)primitiveProperty.TypeUsage.EdmType).PrimitiveTypeKind == PrimitiveTypeKind.DateTime)
{
#>
if(<#=code.FieldName(primitiveProperty)#> == new DateTime())
{
<#=code.FieldName(primitiveProperty)#> = StructuralObject.SetValidValue(value<#=OptionalNullableParameterForSetValidValue(primitiveProperty, code)#>);
<#+
if(ef.IsNullable(primitiveProperty))
{
#>
if(value != null)
<#=code.FieldName(primitiveProperty)#> = DateTime.SpecifyKind(<#=code.FieldName(primitiveProperty)#>.Value, DateTimeKind.Utc);
<#+ }
else
{#>
<#=code.FieldName(primitiveProperty)#> = DateTime.SpecifyKind(<#=code.FieldName(primitiveProperty)#>, DateTimeKind.Utc);
<#+
}
#>
}
else
{
<#=code.FieldName(primitiveProperty)#> = StructuralObject.SetValidValue(value<#=OptionalNullableParameterForSetValidValue(primitiveProperty, code)#>);
}
<#+
}
else
{
#>
<#=code.FieldName(primitiveProperty)#> = StructuralObject.SetValidValue(value<#=OptionalNullableParameterForSetValidValue(primitiveProperty, code)#>);
<#+
}
#>
Мое решение, чтобы гарантировать, что все значения DateTime считываются как Utc DateTimes, выглядит следующим образом:
Я использовал тот же подход, что и Майкл (см. Другой пост в блоге: https://stackoverflow.com/a/9386364/1069313 ) только тогда, когда я нырнул немного глубже и использовал отражение для поиска DateTime и DateTime?
Сначала я написал три метода, которые находятся в моем классе методов DbContext Extensions. Потому что мне нужно использовать его для нескольких DbContexts
public static void ReadAllDateTimeValuesAsUtc(this DbContext context)
{
((IObjectContextAdapter)context).ObjectContext.ObjectMaterialized += ReadAllDateTimeValuesAsUtc;
}
private static void ReadAllDateTimeValuesAsUtc(object sender, ObjectMaterializedEventArgs e)
{
//Extract all DateTime properties of the object type
var properties = e.Entity.GetType().GetProperties()
.Where(property => property.PropertyType == typeof (DateTime) ||
property.PropertyType == typeof (DateTime?)).ToList();
//Set all DaetTimeKinds to Utc
properties.ForEach(property => SpecifyUtcKind(property, e.Entity));
}
private static void SpecifyUtcKind(PropertyInfo property, object value)
{
//Get the datetime value
var datetime = property.GetValue(value, null);
//set DateTimeKind to Utc
if (property.PropertyType == typeof(DateTime))
{
datetime = DateTime.SpecifyKind((DateTime) datetime, DateTimeKind.Utc);
}
else if(property.PropertyType == typeof(DateTime?))
{
var nullable = (DateTime?) datetime;
if(!nullable.HasValue) return;
datetime = (DateTime?)DateTime.SpecifyKind(nullable.Value, DateTimeKind.Utc);
}
else
{
return;
}
//And set the Utc DateTime value
property.SetValue(value, datetime, null);
}
И затем я иду к конструктору моего WebsiteReadModelContext, который является объектом DbContext, и вызываю метод ReadAllDateTimeValuesAsUtc
public WebsiteReadModelContext()
{
this.ReadAllDateTimeValuesAsUtc();
}