如何在 Entity Framework 6 中使用 DbDataReader 获取 table 名称?

How to get table name using DbDataReader in Entity Framework 6?

我的应用程序中有一个自定义 DbDataReader,它会覆盖 GetDateTime 方法以更改 DateTimeKind。

public class MyDbDataReader : BaseDbDataReader
{
    private string _dbName;

    public MyDbDataReader(string dbName, DbDataReader source) : base(source)
    {
        _dbName = dbName;
    }

    public override DateTime GetDateTime(int ordinal)
    {
        var tableName = base.GetSchemaTable().TableName; //this doesn't work
        return DateTime.SpecifyKind(base.GetDateTime(ordinal), base.GetName(ordinal).EndsWith("UTC", StringComparison.OrdinalIgnoreCase) ? DateTimeKind.Utc : DateTimeKind.Local);
    }
}

这是我的 BaseDbDataReader:

public abstract class BaseDbDataReader : DbDataReader
{
    readonly DbDataReader source;
    public BaseDbDataReader(DbDataReader source)
    {
        this.source = source;
    }

    ...
    public override DataTable GetSchemaTable() { return source.GetSchemaTable(); }
}

这个 dbReader 在我的自定义拦截器中使用:

public class MyInterceptor : DbCommandInterceptor
{

    public override void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {           
        base.ReaderExecuted(command, interceptionContext);
        if (!command.Connection.Database.Equals("...") &&
            !(interceptionContext.Result is MyDbDataReader) &&
            interceptionContext.Result != null &&
            interceptionContext.Exception == null)
        {               
            interceptionContext.Result = new MyDbDataReader(command.Connection.Database, interceptionContext.Result);
        }
    }
}

我在这里只想在 GetDateTime 方法中获取 TableName。但是 GetSchemaTable 方法 returns 一个难以理解的结果,其中 TableName 属性 等于“SchemaTable”。我在这里做错了什么以及如何获得正确的 table 名称(如“用户”)。

注意:我不使用 SqlCommand 和 SqlCommand.ExecuteReader 来执行查询。我只是使用 dbSet。即 dbContext.Users.Where(x => x.Id = 1).Single();

TableName 属性 将始终 return "SchemaTable",因为没有其他有意义的名称可以 return.

根据 the link you found,每个列的 table 名称应该 return 编辑在架构 table 的 BaseTableName 列中。但是如果指定了 CommandBehavior.KeyInfo 标志,这只会被 returned。

通过源代码挖掘,看起来你需要使用 ReaderExecuting 方法并接管执行命令的责任才能做到这一点:

public override void ReaderExecuting(
    DbCommand command, 
    DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
    // Skip processing for a specific database:
    if (command.Connection.Database.Equals("...")) return;
    
    var commandBehavior = interceptionContext.CommandBehavior | CommandBehavior.KeyInfo;
    
    try
    {
        var reader = command.ExecuteReader(commandBehavior);
        var result = new MyDbDataReader(command.Connection.Database, reader);
        interceptionContext.Result = result;
    }
    catch (Exception ex)
    {
        interceptionContext.Exception = ex;
    }
}

理论上您应该能够从架构 table:

中提取 BaseTableName
public override DateTime GetDateTime(int ordinal)
{
    var schemaTable = base.GetSchemaTable();
    var tableName = schemaTable.Rows[ordinal].Field<string>("BaseTableName");
    ...
}