sql >> データベース >  >> RDS >> Sqlserver

データベースからのロード時に DateTime.Kind が UTC ではなく unspecified に設定される

    EF6 を使用していて、Kind を設定したいとします。 DateTime のプロパティ データベースから Utc に取得された値 .

    同様の質問が寄せられており、回答は ObjectContext.ObjectMaterialized イベントですが、プロジェクションを使用するクエリでは発生しませんでした。

    私が提案しようとしているソリューションは、DbDataReader で変換を実行することにより、エンティティ クエリとプロジェクション クエリの両方で機能します。 レベル (このタイプのクエリで使用されます)。

    そのためには、カスタムの DbDataReader が必要です GetDateTime 方法。残念ながら DbDataReader を実装しています 派生クラスには多くのボイラープレート コードが必要です。幸いなことに、私はすでに C# 構文エラーを回避するための動的変換 各メソッドを基礎となる DbDataReader に委譲するだけです インスタンスなので、そこから取得します:

    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; } }
    }
    

    その上に必要な実際のクラスを構築します:

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

    それができたら、EF interception<を使用して、EF インフラストラクチャにプラグインする必要があります。 /a> .

    カスタムの DbCommandInterceptor を作成することから始めます 派生クラス:

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

    登録します (たとえば、DbContext から) 派生クラスの静的コンストラクタ):

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

    これで完了です。

    現在、すべての DateTime データベースからの値は Kind になります Utc に設定されたプロパティ .




    1. 一意のIDを指定して、前の行から列が変更された行のみを選択します

    2. C#で部分SQLを字句解析する

    3. MySQL映画予約システム設計パート2

    4. ドロップダウン選択ボックスリストからユーザーが選択したオプションの値をmysqlデータベースに保存するにはどうすればよいですか?