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

Time:09-24

I have a custom DbDataReader in my application, which overrides GetDateTime method to change 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);
    }
}

Here is my BaseDbDataReader:

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

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

This dbReader is used in my custom interceptor:

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

And all i want here, is to get the TableName in GetDateTime method. But GetSchemaTable method returns an incomprehensible result, where the TableName property equals to "SchemaTable". What i'm doing wrong here and how to get correct table name (like "Users").

Note: i dont use SqlCommand and SqlCommand.ExecuteReader to execute queries. I just use dbSet. I.e dbContext.Users.Where(x => x.Id = 1).Single();

CodePudding user response:

The TableName property will always return "SchemaTable", because there's no other meaningful name it can return.

As per the link you found, the table name for each column should be returned in the BaseTableName column of the schema table. But this will only be returned if the CommandBehavior.KeyInfo flag is specified.

Digging through the source code, it looks like you'll need to use the ReaderExecuting method and take over responsibility for executing the command in order to do that:

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

You should theoretically then be able to extract the BaseTableName column from the schema table:

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