Making sure that DateTime properties return DateTimeKind.Utc

后端 未结 3 1322
鱼传尺愫
鱼传尺愫 2021-01-01 05:15

Is it possible to define DateTime properties in entity objects that are of Kind == DateTimeKind.Utc by using either the .edmx file, or a t4 template?

W

相关标签:
3条回答
  • 2021-01-01 05:50

    Yes, it would be possible to use a custom T4 template.

    You'd just have to adjust your property setters and getters.

    It might be easier to attempt a POCO approach;

    For EF1: http://code.msdn.microsoft.com/EFPocoAdapter/Release/ProjectReleases.aspx?ReleaseId=1580

    For EF4: http://thedatafarm.com/blog/data-access/agile-entity-framework-4-repository-part-1-model-and-poco-classes/

    0 讨论(0)
  • 2021-01-01 05:51

    For our case it was impractical to always specify the DateTimeKind as stated previously:

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

    If you want to force all DateTime objects coming out of the database to be specified as UTC you'll need to add a T4 transform file and add additional logic for all DateTime and nullable DateTime objects such that they get initialized as DateTimeKind.Utc

    I have a blog post which explains this step by step: http://www.aaroncoleman.net/post/2011/06/16/Forcing-Entity-Framework-to-mark-DateTime-fields-at-UTC.aspx

    In short:

    1) Create the .tt file for your .edmx model

    2) Open the .tt file and find the "WritePrimitiveTypeProperty" method.

    3) Replace the existing setter code. This is everything between the ReportPropertyChanging and the ReportPropertyChanged method callbacks with the following:

    <#+ 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)#>);
    <#+ 
            }
    #>
    
    0 讨论(0)
  • 2021-01-01 05:52

    My solution to ensure that all the DateTime values are readed as Utc DateTimes is as followed:

    I used the same approach as Michael (see other blog post: https://stackoverflow.com/a/9386364/1069313) only then I dived a little bit deeper, and used reflection to search for DateTime and DateTime?

    First I wrote three methods which are in my DbContext Extensions methods class. Because I need to use it for multiple 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);
    }
    

    And then I go to the constructor of my WebsiteReadModelContext which is a DbContext object and call the ReadAllDateTimeValuesAsUtc method

    public WebsiteReadModelContext()
    {
          this.ReadAllDateTimeValuesAsUtc();
    }
    
    0 讨论(0)
提交回复
热议问题