Chr*_*isR 2 advantage-database-server
下面的代码显示当sql语句为:时,一条记录被删除:
select * from test where qty between 50 and 59
Run Code Online (Sandbox Code Playgroud)
但是sql语句:
select * from test where partno like 'PART/005%'
Run Code Online (Sandbox Code Playgroud)
引发异常:
Advantage.Data.Provider.AdsException: Error 5072: Action requires read-write access to the table
Run Code Online (Sandbox Code Playgroud)
如何应用where子句可靠地删除记录?
注意:我使用的是Advantage Database v9.10.1.9,VS2008,.Net Framework 3.5和WinXP 32位
using System.IO;
using Advantage.Data.Provider;
using AdvantageClientEngine;
using NUnit.Framework;
namespace NetworkEidetics.Core.Tests.Dbf
{
[TestFixture]
public class AdvantageDatabaseTests
{
private const string DefaultConnectionString = @"data source={0};ServerType=local;TableType=ADS_CDX;LockMode=COMPATIBLE;TrimTrailingSpaces=TRUE;ShowDeleted=FALSE";
private const string TestFilesDirectory = "./TestFiles";
[SetUp]
public void Setup()
{
const string createSql = @"CREATE TABLE [{0}] (ITEM_NO char(4), PARTNO char(20), QTY numeric(6,0), QUOTE numeric(12,4)) ";
const string insertSql = @"INSERT INTO [{0}] (ITEM_NO, PARTNO, QTY, QUOTE) VALUES('{1}', '{2}', {3}, {4})";
const string filename = "test.dbf";
var connectionString = string.Format(DefaultConnectionString, TestFilesDirectory);
using (var connection = new AdsConnection(connectionString)) {
connection.Open();
using (var transaction = connection.BeginTransaction()) {
using (var command = connection.CreateCommand()) {
command.CommandText = string.Format(createSql, filename);
command.Transaction = transaction;
command.ExecuteNonQuery();
}
transaction.Commit();
}
using (var transaction = connection.BeginTransaction()) {
for (var i = 0; i < 1000; ++i) {
using (var command = connection.CreateCommand()) {
var itemNo = string.Format("{0}", i);
var partNumber = string.Format("PART/{0:d4}", i);
var quantity = i;
var quote = i * 10;
command.CommandText = string.Format(insertSql, filename, itemNo, partNumber, quantity, quote);
command.Transaction = transaction;
command.ExecuteNonQuery();
}
}
transaction.Commit();
}
connection.Close();
}
}
[TearDown]
public void TearDown()
{
File.Delete("./TestFiles/test.dbf");
}
[Test]
public void CanDeleteRecord()
{
const string sqlStatement = @"select * from test";
Assert.AreEqual(1000, GetRecordCount(sqlStatement));
DeleteRecord(sqlStatement, 3);
Assert.AreEqual(999, GetRecordCount(sqlStatement));
}
[Test]
public void CanDeleteRecordBetween()
{
const string sqlStatement = @"select * from test where qty between 50 and 59";
Assert.AreEqual(10, GetRecordCount(sqlStatement));
DeleteRecord(sqlStatement, 3);
Assert.AreEqual(9, GetRecordCount(sqlStatement));
}
[Test]
public void CanDeleteRecordWithLike()
{
const string sqlStatement = @"select * from test where partno like 'PART/005%'";
Assert.AreEqual(10, GetRecordCount(sqlStatement));
DeleteRecord(sqlStatement, 3);
Assert.AreEqual(9, GetRecordCount(sqlStatement));
}
public int GetRecordCount(string sqlStatement)
{
var connectionString = string.Format(DefaultConnectionString, TestFilesDirectory);
using (var connection = new AdsConnection(connectionString)) {
connection.Open();
using (var command = connection.CreateCommand()) {
command.CommandText = sqlStatement;
var reader = command.ExecuteExtendedReader();
return reader.GetRecordCount(AdsExtendedReader.FilterOption.RespectFilters);
}
}
}
public void DeleteRecord(string sqlStatement, int rowIndex)
{
var connectionString = string.Format(DefaultConnectionString, TestFilesDirectory);
using (var connection = new AdsConnection(connectionString)) {
connection.Open();
using (var command = connection.CreateCommand()) {
command.CommandText = sqlStatement;
var reader = command.ExecuteExtendedReader();
reader.GotoBOF();
reader.Read();
if (rowIndex != 0) {
ACE.AdsSkip(reader.AdsActiveHandle, rowIndex);
}
reader.DeleteRecord();
}
connection.Close();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
LIKE会生成静态游标而不是实时游标,这意味着它是只读数据集。要在这种情况下删除行,最好使用SQL DELETE语句。
DELETE FROM test where partno LIKE 'PART/005%'
Run Code Online (Sandbox Code Playgroud)
我假设您的测试仅此而已。他们使用一些效率不高的机制来定位和删除行。
评论后更新,没有关键字段:
如何使用LEFT标量而不是LIKE(可能并非在所有情况下都适用,但对于您的示例适用)。如果大小始终相同,则还可以在左侧添加一个索引(partno,8)以提高性能:
select * from test where left(partno,8) = 'PART/005'
Run Code Online (Sandbox Code Playgroud)
然后,您可以直接在此实时结果集上使用扩展数据读取器的Delete功能(无需gotop和skip)。
在Alex的ROWID注释之后进行更新 我什至不知道我们的ROWID来自基表,即使在静态游标中也是如此。亚历克斯的评论是解决您的问题的方法。第一:
SELECT t.*, t.rowid FROM test t WHERE x LIKE 'PART/005%'
Run Code Online (Sandbox Code Playgroud)
然后:
DELETE FROM test WHERE rowid = :thisid
Run Code Online (Sandbox Code Playgroud)