以下代码给出了错误(我从catch块中的MessageBox.Show()
得到它)
“PopulateBla()中的异常:存在文件共享冲突 不同的进程可能正在使用文件[,,,,,,]
CODE
using (SqlCeCommand cmd = new SqlCeCommand(SQL_GET_VENDOR_ITEMS, new SqlCeConnection(SQLCE_CONN_STR)))
{
cmd.Parameters.Add("@VendorID", SqlDbType.NVarChar, 10).Value = vendorId;
cmd.Parameters.Add("@VendorItemID", SqlDbType.NVarChar, 19).Value = vendorItemId;
try
{
cmd.Connection.Open();
using (SqlCeDataReader SQLCEReader = cmd.ExecuteReader(CommandBehavior.SingleRow))
{
if (SQLCEReader.Read())
{
itemID = SQLCEReader.GetString(ITEMID_INDEX);
packSize = SQLCEReader.GetString(PACKSIZE_INDEX);
recordFound = true;
}
}
}
catch (SqlCeException err)
{
MessageBox.Show(string.Format("Exception in PopulateControlsIfVendorItemsFound: {0}\r\n", err.Message));//TODO: Remove
}
finally
{
if (cmd.Connection.State == ConnectionState.Open)
{
cmd.Connection.Close();
}
}
}
SQL_GET_VENDOR_ITEMS
是我的查询字符串。
这里可能发生什么文件共享问题?
这种代码使得ctacke推荐的那种重构难以实现:
public void setINVQueryItemGroup( string ID )
{
try
{
dynSQL += " INNER JOIN td_item_group ON t_inv.id = td_item_group.id AND t_inv.pack_size = td_item_group.pack_size WHERE td_item_group.item_group_id = '" + ID + "'";
}
catch( Exception ex )
{
CCR.ExceptionHandler( ex, "InvFile.setINVQueryDept" );
}
}
通过单独的方法附加SQL语句,更改全局var(dynSQL),同时可能允许SQL注入(取决于ID的分配位置/方式)。如果这还不够,任何抛出的异常都可能误导疲惫的bughunter,因为它表明它是以不同的方式发生的(无疑是粗心的复制粘贴操作的受害者)。
这是“编码恐怖” - 值得。在几行代码中你可以忽略多少个最佳实践?
这是另一个例子:
string dynSQL = "SELECT * FROM purgatory WHERE vendor_item = '" + VendorItem + "' ";
if (vendor_id != "")
{
dynSQL += "AND vendor_id = '" + vendor_id + "' ";
}
可以通过用“?”替换args来完成,但是代码然后确定分配哪个/多少个参数将比Joe Garagiola的平均夹板更难42倍。
答案 0 :(得分:1)
如果文件没有标记为只读(你检查过,对吗?),那么你有另一个进程,文件上有非共享锁。
SQL CE附带的isql.exe数据库浏览器是一个常见的罪魁祸首,如果它在后台运行。
根据您的SQLCE版本,很可能另一个进程具有开放连接(无法回想起允许多个进程连接的版本),因此如果您在后台有任何其他应用程序打开它,那么也可能是个问题。
您还使用了大量连接到该数据库,并且它们并不总是被清理并立即释放到Dispose。我强烈建议构建一个简单的连接管理器类,它保持与数据库的单个(或更像两个)连接,并且只是为所有操作重用它们。
答案 1 :(得分:1)
我真的很喜欢Chris使用单一连接到数据库的想法。您可以像这样向您的类声明全局:
public ClayShannonDatabaseClass
{
private SqlCeConnection m_openConnection;
public ClayShannonDatabaseClass()
{
m_openConnection = new SqlCeConnection();
m_openConnection.Open();
}
public void Dispose()
{
m_openConnection.Close();
m_openConnection.Dispose();
m_openConnection = null;
}
}
我猜你的代码在你试图实际打开数据库时会崩溃。
要验证这一点,您可以在代码中粘贴一个整数值以帮助您进行调试。
示例:
int debugStep = 0;
try
{
//cmd.Connection.Open(); (don't call this if you use m_openConnection)
debugStep = 1;
using (SqlCeDataReader SQLCEReader = cmd.ExecuteReader(CommandBehavior.SingleRow))
{
debugStep = 2;
if (SQLCEReader.Read())
{
debugStep = 3;
itemID = SQLCEReader.GetString(ITEMID_INDEX);
debugStep = 4;
packSize = SQLCEReader.GetString(PACKSIZE_INDEX);
debugStep = 5;
recordFound = true;
}
}
}
catch (SqlCeException err)
{
string msg = string.Format("Exception in PopulateControlsIfVendorItemsFound: {0}\r\n", err.Message);
string ttl = string.Format("Debug Step: {0}", debugStep);
MessageBox.Show(msg, ttl); //TODO: Remove
}
// finally (don't call this if you use m_openConnection)
// {
// if (cmd.Connection.State == ConnectionState.Open)
// {
// cmd.Connection.Close();
// }
// }
我猜测你的错误是在第1步。