EOF或BOF为真,但记录计数大于零
本文关键字:大于 记录 BOF 为真 EOF | 更新日期: 2023-09-27 18:32:41
我在 C# 中使用记录集,因为我的 DLL 将被 VBA 应用程序使用。我正在使用 ADO.NET 从数据库中获取数据并手动填充记录集。这部分工作正常,我使用 MoveFirst(),我可以浏览记录。
但是我需要对数据进行排序,并且在设置记录集的 Sort 属性后,我不能再使用它了。它说 BOF 或 EOF 都是真的,但记录计数接近 300.000,所以我的记录集有数据!为什么在我设置 Sort 属性后会发生这种情况?
我无法对数据库进行排序,因为我使用的数据库过程不是我的,我无法访问它。
代码示例:
过程调用和记录集创建:
ADODB.Recordset ExecuteProcedure(string procedure, List<SqlParameter> parameters, List<Alias> alias)
{
SqlCommand commando = new SqlCommand(procedure, this.Connection);
commando.CommandType = CommandType.StoredProcedure;
commando.CommandTimeout = this.TimeOut;
if (parameters != null)
{
foreach (SqlParameter param in parameters)
{ commando.Parameters.Add(param); }
};
SqlDataReader dr = commando.ExecuteReader();
ADODB.Recordset result = new ADODB.Recordset();
result.CursorLocation = ADODB.CursorLocationEnum.adUseClient;
//create columns
foreach (var item in alias.OrderBy(o => o.ColumnIndex).ToList())
{
Type fieldType = null;
for (int i = 0; i < dr.FieldCount; i++)
{
if (dr.GetName(i).Equals(item.ColumnName))
{
fieldType = dr.GetFieldType(i);
break;
}
}
result.Fields.Append(item.Alias
, TranslateType(fieldType)
, fieldType == typeof(String) ? 16384 : (fieldType == typeof(DateTime) ? 0 : int.MaxValue)
, ADODB.FieldAttributeEnum.adFldIsNullable
, null);
}
result.Open(System.Reflection.Missing.Value, System.Reflection.Missing.Value
, ADODB.CursorTypeEnum.adOpenStatic, ADODB.LockTypeEnum.adLockOptimistic, 0);
while (dr.Read())
{
result.AddNew(System.Reflection.Missing.Value, System.Reflection.Missing.Value);
foreach (var item in alias.OrderBy(o => o.ColumnIndex).ToList())
{
result.Fields[item.ColumnIndex - 1].Value = dr[item.ColumnName];
}
}
dr.Close();
return result;
}
调用方法:
var rs = myAccessManager.ExecuteProcedure("procedure", param, StringToDatatableAlias(colunas));
if (!rs.BOF)
rs.MoveFirst();
//until this point, I can see de data on Immediate window. Everything is working fine
if(!String.IsNullOrEmpty(orderBy))
rs.Sort = orderBy;
//after this point, I get the BOF or EOF are both true error when I try to access de data on recordset. But recordcount property is still above 300.000
我已经找到了问题和解决方案。我在这里写为什么会发生这种情况,以及如何解决将来有人遇到这种情况。
首先,问题是由我创建记录集字段的方式引起的。特别是这一行:
result.Fields.Append(item.Alias
, TranslateType(fieldType)
, fieldType == typeof(String) ? 16384 : (fieldType == typeof(DateTime) ? 0 : int.MaxValue)
, ADODB.FieldAttributeEnum.adFldIsNullable
, null);
我使用此子句定义了字段长度 fieldType == typeof(String) ? 16384 : (fieldType == typeof(DateTime) ? 0 : int.MaxValue)
字段太大。如此之大,以至于记录集无法排序并给出例外。它只是得到了EOF和BOF =true,记录集变得不可用。
那么我做了什么来解决这个问题呢?我使用了数据库字段中的元数据信息来定义记录集字段的长度。
代码的结尾如下:
ADODB.Recordset ExecuteProcedure(string procedure, List<SqlParameter> parameters, List<Alias> alias)
{
SqlCommand commando = new SqlCommand(procedure, this.Connection);
commando.CommandType = CommandType.StoredProcedure;
commando.CommandTimeout = this.TimeOut;
if (parameters != null)
{
foreach (SqlParameter param in parameters)
{ commando.Parameters.Add(param); }
};
SqlDataReader dr = commando.ExecuteReader();
ADODB.Recordset result = new ADODB.Recordset();
result.CursorLocation = ADODB.CursorLocationEnum.adUseClient;
//get table schema
DataTable schema = dr.GetSchemaTable();
foreach (var item in alias.OrderBy(o => o.ColumnIndex).ToList())
{
Type fieldType = dr.GetFieldType(dr.GetOrdinal(item.ColumnName));
result.Fields.Append(item.Alias
, TranslateType(fieldType)
, Convert.ToInt32(schema.Rows[dr.GetOrdinal(item.ColumnName)]["ColumnSize"])
, schema.Rows[dr.GetOrdinal(item.ColumnName)]["AllowDBNull"].ToString().ToLower().Equals("true") ? ADODB.FieldAttributeEnum.adFldIsNullable : ADODB.FieldAttributeEnum.adFldUnspecified
, null);
}
result.Open(System.Reflection.Missing.Value, System.Reflection.Missing.Value
, ADODB.CursorTypeEnum.adOpenStatic, ADODB.LockTypeEnum.adLockOptimistic, 0);
while (dr.Read())
{
result.AddNew(System.Reflection.Missing.Value, System.Reflection.Missing.Value);
foreach (var item in alias.OrderBy(o => o.ColumnIndex).ToList())
{
result.Fields[item.ColumnIndex - 1].Value = dr[item.ColumnName];
}
}
dr.Close();
return result;
}