【发布时间】:2017-12-24 17:10:07
【问题描述】:
我使用 Microsoft SQL Server 迁移助手将 Access 数据库迁移到 SQL。
现在,我无法读取数据。
return reader.GetInt32(0); 在检索到 32 行后抛出 Invalid attempt to read when no data is present 异常。如果我将CommandBehavior.SequentialAccess 添加到我的命令中,我可以读取 265 行,每次。
数据
查询(在 SQL Management Studio 中):
SELECT *
FROM Products2
WHERE Products2.PgId = 337;
第 32 行没有什么特别之处,如果我颠倒顺序,仍然是第 32 行杀死它。
第 265 行,仅供参考。
代码
查询:
SELECT *
FROM Products2
WHERE Products2.PgId = @productGroupId;
参数:
Name = "productGroupId"
Value = 337
执行:
public async Task ExecuteAsync(string query, Action<IDataReader> onExecute, params DataParameter[] parameters)
{
using(var command = builder.BuildCommand(query))
{
foreach(var parameter in parameters)
command.AddParameter(parameter);
if(!connection.IsOpen)
connection.Open();
await Task.Run(async () =>
{
using(var reader = await command.ExecuteAsync())
if(await reader.ReadAsync())
onExecute(reader);
});
}
}
阅读:
await executor.ExecuteAsync(query, async reader =>
{
do
{
products.Add(GetProduct(reader));
columnValues.Enqueue(GetColumnValues(reader).ToList());
} while(await reader.ReadAsync());
}, parameters.ToArray());
await reader.ReadAsync() 返回 true,但是当 GetProduct(reader) 第 32 次调用 reader.GetInt32(0); 时,它会抛出异常。
如果数据少于 32 行,则可以正常工作,如果是 SequentialAccess,则为 265。
我尝试增加CommandTimeout,但没有帮助。当我再次将连接交换到OleDb 时,它工作得很好。
提前致谢。
编辑
如果我只用几个特定列替换查询中的*,它就可以工作。当我阅读 ~12 列时,它失败了,但晚于第 32 行。
根据要求,GetProduct:
private Product GetProduct(IDataReader productReader)
{
return new Product
{
Id = productReader.ReadLong(0),
Number = productReader.ReadString(2),
EanNo = productReader.ReadString(3),
Frequency = productReader.ReadInt(4),
Status = productReader.ReadInt(5),
NameId = productReader.ReadLong(6),
KMPI = productReader.ReadByte(7),
OEM = productReader.ReadString(8),
CurvesetId = productReader.ReadInt(9),
HasServiceInfo = Convert.ToBoolean(productReader.ReadByte(10)),
ColumnData = new List<ColumnData>()
};
}
获取列数据:
private IEnumerable<long> GetColumnValues(IDataReader productReader)
{
var columnValues = new List<long>();
int columnIndex = 11;
while(!productReader.IsNull(columnIndex))
columnValues.Add(productReader.ReadLong(columnIndex++));
return columnValues;
}
还有适配器:
public long ReadLong(int columnIndex)
{
return reader.GetInt32(columnIndex);
}
好的,时间越来越长了。 :) 感谢@Igor,我尝试创建一个小的工作示例。这似乎工作正常:
private static async Task Run()
{
var result = new List<Product>();
string conString = @" ... ";
var con = new SqlConnection(conString);
con.Open();
using(var command = new SqlCommand("SELECT * FROM Products2 WHERE Products2.PgId = @p;", con))
{
command.Parameters.Add(new SqlParameter("p", 337));
await Task.Run(async () =>
{
using(var productReader = await command.ExecuteReaderAsync())
while(await productReader.ReadAsync())
{
result.Add(new Product
{
Id = productReader.GetInt32(0),
Number = productReader.GetString(2),
EanNo = productReader.GetString(3),
Frequency = productReader.GetInt16(4),
Status = productReader.GetInt16(5),
NameId = productReader.GetInt32(6),
KMPI = productReader.GetByte(7),
OEM = productReader.GetString(8),
CurvesetId = productReader.GetInt16(9),
HasServiceInfo = Convert.ToBoolean(productReader.GetByte(10))
});
GetColumnValues(productReader);
}
});
}
Console.WriteLine("End");
}
private static IEnumerable<long> GetColumnValues(SqlDataReader productReader)
{
var columnValues = new List<long>();
int columnIndex = 11;
while(!productReader.IsDBNull(columnIndex))
columnValues.Add(productReader.GetInt32(columnIndex++));
return columnValues;
}
}
这是 Access 中的数据,以防万一:
【问题讨论】:
-
不要异步,你的问题可能会消失。
-
@BensaysNotoPoliticsonSO,你建议我如何让它保持响应?
-
通过正确索引它以便快速查询。
-
我无法控制数据库的原理图。
-
至于最后一列,您是说一旦遇到
null/DBNull.Value,那么所有后续列的值也将为空?如果不是这种情况,那么这将是一个可能的失败点。