我们使用包装IDbConnection / IDbCommand的装饰器广泛地缓存我们的查询。当某些东西调用'ExecuteReader()'时,它使用command.text作为缓存键(例如SELECT * FROM Foo
),我们也可以将标记应用于我们的装饰器(例如new FooDbCommand("UserCacheTag")
)来管理它。 Reader被转换为DataTable,可以进行明显的序列化,并使用DataTables api(CreateDataReader)进行转换。
这一切都很出色,但有一个缺陷。
如果传入的记录集具有重复的列名,当IDataReader被转换为DataTable时,重复的列名称将以数字递增(例如“PersonID1”)。
我们如何制作IDataReader,它允许重复的列名,可缓存(优选可序列化),然后将其转换回具有原始列名的IDataReader,而不必担心在各州之间更改列名?
其他信息:
我们主要使用Dapper和动态返回类型来避免这些问题。我们想开始更多地使用多重映射。但是,如果在一个查询中多次返回一个类型,例如“Person”,则会出现重复的列名。
例如:
SELECT pEmployee.*, pManager.*
FROM Persons pEmployee
LEFT OUTER JOIN Persons pManager ON pManager.PersonID = pEmployee.ManagerPersonID
答案 0 :(得分:0)
我通过创建自己的DataTable类来完成此操作,该类将原始列名称存储到' Caption' property和我自己的IDataReader,它覆盖GetName()方法以查看模式表。它非常简单,但我确实希望DataTable只有一个“AllowDuplicateColumnNames”和#39; AllowDuplicateColumnNames'属性。
<强> MyDataTable 强>
加载DataReader时,会设置&#39; Caption&#39;属性到原始列名称。创建DataReader时,它将重命名&#39; ColumnName&#39; schematable的属性返回原始名称(当前存储在Caption列中)。
internal class MyDataTable : DataTable
{
public MyDataTable()
{
}
/// <summary>
/// This is a helper method which accounts for duplicate column names.
/// In the loading process, it will rewrite the caption to be the original column name
/// which can be a duplicate.
/// </summary>
/// <param name="dataReader"></param>
public void LoadIDataReader(IDataReader dataReader)
{
var schemaTable = dataReader.GetSchemaTable();
base.Load(dataReader);
for (var i = 0; i < schemaTable.Rows.Count; i++)
{
var originalColumnName = schemaTable.Rows[i]["ColumnName"] as string;
var currentColumnName = this.Columns[i].ColumnName;
if(originalColumnName != currentColumnName)
{
this.Columns[i].Caption = originalColumnName;
}
}
}
public IDataReader CreateIDataReader()
{
var dataReader = base.CreateDataReader();
var schemaTable = dataReader.GetSchemaTable();
for(var i = 0; i < schemaTable.Rows.Count; i++)
{
//this is reverse from above
var originalColumnName = this.Columns[i].Caption;
var currentColumnName = schemaTable.Rows[i]["ColumnName"] as string;
if (originalColumnName != currentColumnName)
{
schemaTable.Rows[i]["ColumnName"] = originalColumnName;
}
}
return new MyDataReader(dataReader);
}
}
MyDataReader:IDataReader
这接受一个datareader,只是充当GetName()方法的装饰器。
internal class MyDataReader : IDataReader
{
private IDataReader _dataReader;
public MyDataReader(IDataReader dataReader)
{
_dataReader = dataReader;
}
//other IDataReader methods not included for clarity
public string GetName(int i)
{
return this.GetSchemaTable().Rows[i]["ColumnName"] as string;
}
}