Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

DateTime.Kind được đặt thành không xác định, không phải UTC, khi tải từ cơ sở dữ liệu

Giả sử bạn đang sử dụng EF6 và bạn muốn đặt Kind thuộc tính của bất kỳ DateTime nào giá trị được truy xuất từ ​​cơ sở dữ liệu đến Utc .

Các câu hỏi tương tự đã được đặt ra và câu trả lời có xu hướng gợi ý kết nối với ObjectContext.ObjectMaterialized nhưng nó không kích hoạt cho các truy vấn sử dụng phép chiếu.

Giải pháp mà tôi sẽ đề xuất hoạt động cho cả truy vấn thực thể và phép chiếu, bằng cách thực hiện chuyển đổi tại DbDataReader cấp (được sử dụng bởi loại truy vấn này).

Để làm được điều đó, chúng tôi cần một DbDataReader tùy chỉnh triển khai chặn GetDateTime phương pháp. Thật không may khi triển khai DbDataReader lớp dẫn xuất yêu cầu rất nhiều mã soạn sẵn. May mắn thay, tôi đã tạo một biểu mẫu lớp cơ sở, câu trả lời của tôi cho Dịch động để tránh lỗi cú pháp C # mà chỉ cần ủy quyền từng phương thức cho DbDataReader bên dưới ví dụ, vì vậy tôi sẽ chỉ lấy nó từ đó:

abstract class DelegatingDbDataReader : DbDataReader
{
    readonly DbDataReader source;
    public DelegatingDbDataReader(DbDataReader source)
    {
        this.source = source;
    }
    public override object this[string name] { get { return source[name]; } }
    public override object this[int ordinal] { get { return source[ordinal]; } }
    public override int Depth { get { return source.Depth; } }
    public override int FieldCount { get { return source.FieldCount; } }
    public override bool HasRows { get { return source.HasRows; } }
    public override bool IsClosed { get { return source.IsClosed; } }
    public override int RecordsAffected { get { return source.RecordsAffected; } }
    public override bool GetBoolean(int ordinal) { return source.GetBoolean(ordinal); }
    public override byte GetByte(int ordinal) { return source.GetByte(ordinal); }
    public override long GetBytes(int ordinal, long dataOffset, byte[] buffer, int bufferOffset, int length) { return source.GetBytes(ordinal, dataOffset, buffer, bufferOffset, length); }
    public override char GetChar(int ordinal) { return source.GetChar(ordinal); }
    public override long GetChars(int ordinal, long dataOffset, char[] buffer, int bufferOffset, int length) { return source.GetChars(ordinal, dataOffset, buffer, bufferOffset, length); }
    public override string GetDataTypeName(int ordinal) { return source.GetDataTypeName(ordinal); }
    public override DateTime GetDateTime(int ordinal) { return source.GetDateTime(ordinal); }
    public override decimal GetDecimal(int ordinal) { return source.GetDecimal(ordinal); }
    public override double GetDouble(int ordinal) { return source.GetDouble(ordinal); }
    public override IEnumerator GetEnumerator() { return source.GetEnumerator(); }
    public override Type GetFieldType(int ordinal) { return source.GetFieldType(ordinal); }
    public override float GetFloat(int ordinal) { return source.GetFloat(ordinal); }
    public override Guid GetGuid(int ordinal) { return source.GetGuid(ordinal); }
    public override short GetInt16(int ordinal) { return source.GetInt16(ordinal); }
    public override int GetInt32(int ordinal) { return source.GetInt32(ordinal); }
    public override long GetInt64(int ordinal) { return source.GetInt64(ordinal); }
    public override string GetName(int ordinal) { return source.GetName(ordinal); }
    public override int GetOrdinal(string name) { return source.GetOrdinal(name); }
    public override string GetString(int ordinal) { return source.GetString(ordinal); }
    public override object GetValue(int ordinal) { return source.GetValue(ordinal); }
    public override int GetValues(object[] values) { return source.GetValues(values); }
    public override bool IsDBNull(int ordinal) { return source.IsDBNull(ordinal); }
    public override bool NextResult() { return source.NextResult(); }
    public override bool Read() { return source.Read(); }
    public override void Close() { source.Close(); }
    public override T GetFieldValue<T>(int ordinal) { return source.GetFieldValue<T>(ordinal); }
    public override Task<T> GetFieldValueAsync<T>(int ordinal, CancellationToken cancellationToken) { return source.GetFieldValueAsync<T>(ordinal, cancellationToken); }
    public override Type GetProviderSpecificFieldType(int ordinal) { return source.GetProviderSpecificFieldType(ordinal); }
    public override object GetProviderSpecificValue(int ordinal) { return source.GetProviderSpecificValue(ordinal); }
    public override int GetProviderSpecificValues(object[] values) { return source.GetProviderSpecificValues(values); }
    public override DataTable GetSchemaTable() { return source.GetSchemaTable(); }
    public override Stream GetStream(int ordinal) { return source.GetStream(ordinal); }
    public override TextReader GetTextReader(int ordinal) { return source.GetTextReader(ordinal); }
    public override Task<bool> IsDBNullAsync(int ordinal, CancellationToken cancellationToken) { return source.IsDBNullAsync(ordinal, cancellationToken); }
    public override Task<bool> ReadAsync(CancellationToken cancellationToken) { return source.ReadAsync(cancellationToken); }
    public override int VisibleFieldCount { get { return source.VisibleFieldCount; } }
}

và xây dựng lớp thực tế mà chúng ta cần trên đó:

class UtcDateTimeConvertingDbDataReader : DelegatingDbDataReader
{
    public UtcDateTimeConvertingDbDataReader(DbDataReader source) : base(source) { }
    public override DateTime GetDateTime(int ordinal)
    {
        return DateTime.SpecifyKind(base.GetDateTime(ordinal), DateTimeKind.Utc);
    }
}

Sau khi có điều đó, chúng tôi cần cắm nó vào cơ sở hạ tầng EF bằng cách sử dụng EF chặn .

Chúng ta sẽ bắt đầu bằng cách tạo DbCommandInterceptor tùy chỉnh lớp dẫn xuất:

class UtcDateTimeConvertingDbCommandInterceptor : DbCommandInterceptor
{
    public override void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {
        base.ReaderExecuted(command, interceptionContext);
        if (!(interceptionContext.Result is UtcDateTimeConvertingDbDataReader)
            && interceptionContext.Result != null
            && interceptionContext.Exception == null)
            interceptionContext.Result = new UtcDateTimeConvertingDbDataReader(interceptionContext.Result);
    }
}

đăng ký nó (ví dụ:từ DbContext của bạn phương thức khởi tạo tĩnh của lớp dẫn xuất):

public class YourDbContext : DbContext
{
    static YourDbContext()
    {
        DbInterception.Add(new UtcDateTimeConvertingDbCommandInterceptor());
    }
    // ...
}

và chúng tôi đã hoàn thành.

Bây giờ mọi DateTime giá trị đến từ cơ sở dữ liệu sẽ có Kind thuộc tính được đặt thành Utc .




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Nhóm SQL và Tổng theo tháng - Mặc định là 0

  2. Bảng tổng hợp động với nhiều cột trong máy chủ sql

  3. Chèn varchar đã chuyển đổi vào sql datetime

  4. Cách tìm tên máy chủ cho SQL Server 2005

  5. Cách tốt nhất để truy vấn từ điển dữ liệu trong sql