Этот ответ работает с Entity Framework 6
Принятый ответ не работает для проектируемого или анонимного объекта. Производительность тоже может быть проблемой.
Для этого нам нужно использовать DbCommandInterceptor
объект, предоставляемый EntityFramework.
Создать перехватчик:
public class UtcInterceptor : DbCommandInterceptor
{
public override void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
base.ReaderExecuted(command, interceptionContext);
if (interceptionContext?.Result != null && !(interceptionContext.Result is UtcDbDataReader))
{
interceptionContext.Result = new UtcDbDataReader(interceptionContext.Result);
}
}
}
interceptionContext.Result
это DbDataReader, который мы заменяем нашим
public class UtcDbDataReader : DbDataReader
{
private readonly DbDataReader source;
public UtcDbDataReader(DbDataReader source)
{
this.source = source;
}
public override DateTime GetDateTime(int ordinal)
{
return DateTime.SpecifyKind(source.GetDateTime(ordinal), DateTimeKind.Utc);
}
public new void Dispose()
{
source.Dispose();
}
public new IDataReader GetData(int ordinal)
{
return source.GetData(ordinal);
}
}
Зарегистрируйте перехватчик в своем DbConfiguration
internal class MyDbConfiguration : DbConfiguration
{
protected internal MyDbConfiguration ()
{
AddInterceptor(new UtcInterceptor());
}
}
Наконец, зарегистрируйте конфигурацию на вашем DbContext
[DbConfigurationType(typeof(MyDbConfiguration ))]
internal class MyDbContext : DbContext
{
}
Вот и все. Ура.
Для простоты вот полная реализация DbReader:
using System;
using System.Collections;
using System.Data;
using System.Data.Common;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace MyNameSpace
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1010:CollectionsShouldImplementGenericInterface")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
public class UtcDbDataReader : DbDataReader
{
private readonly DbDataReader source;
public UtcDbDataReader(DbDataReader source)
{
this.source = source;
}
public override int VisibleFieldCount => source.VisibleFieldCount;
public override int Depth => source.Depth;
public override int FieldCount => source.FieldCount;
public override bool HasRows => source.HasRows;
public override bool IsClosed => source.IsClosed;
public override int RecordsAffected => source.RecordsAffected;
public override object this[string name] => source[name];
public override object this[int ordinal] => source[ordinal];
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 DateTime.SpecifyKind(source.GetDateTime(ordinal), DateTimeKind.Utc);
}
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);
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1816:CallGCSuppressFinalizeCorrectly")]
public new void Dispose()
{
source.Dispose();
}
public new IDataReader GetData(int ordinal)
{
return source.GetData(ordinal);
}
}
}