我在LIBRARY1.TRACKINGTABLE的AS400系统上有一个跟踪表。该表有5个字段:
在我的应用程序中,在处理过程中,我提示用户是否希望将处理过的文档提交到图像文件服务器。如果单击“是”,则会将所有已处理的文档从C:中的本地文件夹移动到共享网络文件夹。
然后,我在处理过的文档中包含了所有SSN的数组。对于数组中的每个SSN,我调用一个名为updateAddrChangHistory(ssn)
的函数来更新我的跟踪表:
// PROMPT USER TO COMMIT
DialogResult dResult = MessageBox.Show("Mail Merge Completed. Individual Documents Saved to C:\\TEMP\\to fyi\\. \n\n Commit generated documents to NetFYI?", "Confirm Commit", MessageBoxButtons.YesNo);
if (dResult == DialogResult.Yes)
{
moveLocalToCommitFYI();
// If selected letter is New/Old Address Letter, and thus tracked in table LIBRARY.TRACKINGTABLE,
// update the tracking table using SSN's stored in SSNsArray.
if (cmbLetterType.SelectedIndex < 2)
{
// Now that user has "theoretically" printed and Commited the processed documents, update Change History Table
foreach (string ssn in SSNsArray)
{
if (ssn != null && ssn.Length > 0)
{
updateAddrChngHistory(ssn);
}
}
}
SSNsArray = new string[0]; // Clear the array for next processing
updatePrintedCntLabel();
}
然后,根据处理的文档类型,我要么INSERT新记录(表示已打印新地址字母),要么UPDATE记录(表示已为同一成员打印旧地址字母)。
public void updateAddrChngHistory(string SSN)
{
// Update/Modify Tracking Table
string formattedDate = dtpDate.Value.ToString("yyyyMMdd");
//string formattedTime = DateTime.Now.TimeOfDay.ToString("HHmmss");
string query = "";
switch (docType)
{
case "oldAddr":
query = "UPDATE LIBRARY.TRACKINGTABLE SET PRINT_OLD = CURRENT_TIMESTAMP WHERE SSN = " + SSN + " AND PRINT_OLD IS NULL";
break;
case "newAddr":
query = "INSERT INTO LIBRARY.TRACKINGTABLE (SSN, DATE, TIME, PRINT_NEW, PRINT_OLD) VALUES (" + SSN + ", " + formattedDate + ", " + System.DateTime.Now.ToString("HHmmss") + ", CURRENT_TIMESTAMP, NULL)";
break;
case "nameChg":
break;
case "nameChgWAR":
break;
}
mdl.InsertUpdateData(query);
// Close Connection
mdl.closeConn();
}
mdl.InsertUpdateDate()
是一个类文件函数:
namespace MergeDoc
{
public class MergeDocClassLibrary
{
OdbcConnection conn = new OdbcConnection();
public void InsertUpdateData(string query)
{
// PROD
string connString = "DRIVER=Client Access ODBC Driver (32-bit); SYSTEM=XX.XX.X.XX; UID=XYXYXYZ; PWD=YXZYXZY";
// DEV
//string connString = ""
OdbcCommand cmd = new OdbcCommand(query, conn);
// Set connection using connectionString
conn.ConnectionString = connString;
// Open Connection
conn.Open();
// Execute command and store in OBDC DataReader
cmd.ExecuteReader();
}
}
}
我的问题是以下:
我的最终用户在虚拟机上。当他们运行应用程序时,假设处理97个新的地址字母记录,72将使其进入跟踪表。每次,在处理的某个时刻,他们都会收到以下错误(AFTER文档成功移动到图像服务器处理文件夹):
我可以说,这源于我的INSERT语句。然而,我无法弄清楚的是,为什么有几条记录成功进入表中,然后突然之间会出现这种错误。更令人沮丧的是,我似乎无法在我自己的机器上复制错误(即使清除跟踪表并处理与我的用户完全相同的记录)。
有没有其他人有此错误的经验?有什么想法来解决这个问题?
SSN是已处理的SSN,DATE是从我的应用程序datepicker控件中选择的日期,TIME是当前系统时间,print new是当前日期时间。这四个字段都是NON-NULL,应该共同创建一个完全唯一的值。
答案 0 :(得分:3)
此代码存在很多问题
应该在打开之前测试打开的连接。
为什么要打开连接?
你可以使用一些错误捕获
您将知道错误,并且应该能够获得更多细节
您不应该使用ExecuteReader()进行更新或插入
更新或插入应该是ExecuteNonQuery()
基于更新和插入语句,最有可能SSN是PK
如果docType是newAddr而没有检查SSN是否存在,则表示您正在执行插入。
if(string.IsNullOrEmpty(query)) return;
try
{
OdbcCommand cmd = new OdbcCommand(query, conn);
conn.ConnectionString = connString;
conn.Open();
cmd.ExecuteReader();
}
catch (OdbcException Ex)
{
Debug.WriteLine(Ex.Message);
throw Ex;
}
finally
{ }
答案 1 :(得分:2)
这是SQL问题的一个更清晰的消息。您不能添加具有与现有行相同的SSN的新行。现有的行可能已存在10年,或者它可能是您刚刚在抛出异常的行之前添加的行。
switch()可能会让您陷入困惑的路径。无论某些外部进程声明“旧”或“新”地址,此代码都需要更新现有行并添加不存在的行。想象一下这种情况。外部进程看到SSN 123进来。它检查文件,123不在那里。因此它将交易标记为“新”。然后,5个文档之后,处理SSN 123的另一个传入文档。外部进程检查文件,123不在那里,因此它也将此事务标记为“新”。当你到处调用updateAddrChngHistory时,SSN 123的第一个实例被INSERT了很好,但是后来有5个文件,SSN 123的下一个实例是重复的,INSERT失败了。这只是一种可能发生的方式。
如果您不想捕获重复键异常,则需要在SQL中对其进行测试:
INSERT INTO LIBRARY.TRACKINGTABLE
(SSN, DATE, TIME, PRINT_NEW, PRINT_OLD)
VALUES (" + SSN + ", " + formattedDate + ", " +
System.DateTime.Now.ToString("HHmmss") + ", CURRENT_TIMESTAMP, NULL)
where ssn not in (select ssn from library.trackingtable)