S'assurer que les propriétés DateTime renvoient DateTimeKind.Utc

.net-4.0 entity-framework linq-to-entities

Question

Est-il possible de définir des propriétés DateTime dans des objets d'entité de Kind == DateTimeKind.Utc à l'aide du fichier .edmx ou d'un modèle t4?

Si possible en utilisant t4, veuillez décrire comment modifier la propriété. Actuellement, la propriété est générée sous la forme:

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

Réponse acceptée

Dans notre cas, il n’était pas pratique de toujours spécifier le DateTimeKind comme indiqué précédemment:

DateTime utcDateTime = DateTime.SpecifyKind(databaseDateTime, DateTimeKind.Utc);

Si vous souhaitez que tous les objets DateTime sortant de la base de données soient spécifiés au format UTC, vous devez ajouter un fichier de transformation T4 et ajouter une logique supplémentaire pour tous les objets DateTime et DateTime nullable, de sorte qu'ils soient initialisés sous DateTimeKind.Utc

J'ai un article de blog qui explique cette étape par étape: http://www.aaroncoleman.net/post/2011/06/16/Forcing-Entity-Framework-to-mark-DateTime-fields-at-UTC.aspx

En bref:

1) Créez le fichier .tt pour votre modèle .edmx

2) Ouvrez le fichier .tt et trouvez la méthode "WritePrimitiveTypeProperty".

3) Remplacez le code de poseur existant. C'est tout ce qui se situe entre les rappels de méthode ReportPropertyChanging et ReportPropertyChanged avec les éléments suivants:

<#+ 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)#>);
<#+ 
        }
#>

Réponse populaire

Ma solution pour m'assurer que toutes les valeurs DateTime sont lues comme Utc DateTimes est la suivante:

J'ai utilisé la même approche que Michael (voir autre billet: https://stackoverflow.com/a/9386364/1069313 ) seulement après que j'ai plongé un peu plus profondément et utilisé la réflexion pour rechercher DateTime et DateTime?

J'ai d'abord écrit trois méthodes qui sont dans ma classe de méthodes DbContext Extensions. Parce que j'ai besoin de l'utiliser pour plusieurs 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);
}

Et puis je vais au constructeur de mon WebsiteReadModelContext qui est un objet DbContext et appelle la méthode ReadAllDateTimeValuesAsUtc

public WebsiteReadModelContext()
{
      this.ReadAllDateTimeValuesAsUtc();
}


Related

Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow