我的子系统正在接收要在表中可视化的 SQL 查询。我使用 DataTable 是因为我无法控制要可视化的 SQL 查询,并且它们可以轻松地显示在 DataGrid 中。
我基本上拥有的是:
var query = "SELECT 1";
var connection = new SqlConnection(connectionString);
var adapter = new SqlDataAdapter(query, connection);
var table = new DataTable();
adapter.Fill(table);
Console.WriteLine(table.Columns[0].ColumnName);
在这种情况下,DataTable 中的列名称将设置为
Column1
,因为输入查询未指定该列的名称。
如何确定列名实际上是
Column1
还是由于查询未指定列名而由 SqlDataAdapter
实现生成?
我的第一次尝试是检查
Column(N)
,但我意识到这并不可靠。如果查询实际上指定了名称 Column1
怎么办?我还担心“Column”可能会被翻译为 .NET 框架本地化版本的其他内容。
我还考虑过解析输入 SQL 以确定列的命名方式,但这很快就会变得困难和/或容易出错。
使用
SqlDataReader
可以获得实际的列名称。这就是 SqlDataAdapter
使用的。问题是 SqlDataReader
实例无法从 SqlDataAdapter
外部访问。
我的解决方案是重新实现
SqlDataAdapter.Fill
方法所需的基本功能来设置实际的列名称。
我必须使用
Caption
属性而不是 ColumnName
属性,因为 DataTable
实现会将 ColumnName
属性值自动更改为 Column1
,因为似乎需要 ColumnName
属性非空且唯一。
最小
Fill
实施:
var query = "SELECT 1";
var connection = new SqlConnection(connectionString);
connection.Open();
var table = new DataTable();
// Fill
var command = new SqlCommand(query, connection);
var reader = command.ExecuteReader();
var fieldCount = reader.FieldCount;
for (var index = 0; index < fieldCount; index++)
{
var name = reader.GetName(index);
var fieldType = reader.GetFieldType(index);
table.Columns.Add(new DataColumn { ColumnName = name, Caption = name, DataType = fieldType });
}
var valuesBuffer = new object[fieldCount];
while (reader.Read())
{
reader.GetValues(valuesBuffer);
table.Rows.Add(valuesBuffer);
}
Console.WriteLine(table.Columns[0].Caption); // Output: <empty string>