【问题标题】:Why would this query generate a file sharing violation?为什么这个查询会产生文件共享冲突?
【发布时间】:2013-03-25 13:22:25
【问题描述】:

下面的代码给了我错误(我从 catch 块中的 MessageBox.Show() 得到它)

"PopulateBla() 中的异常:存在文件共享冲突。A 不同的进程可能正在使用文件 [,,,,,,]

代码

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 语句,更改全局变量 (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 倍。

【问题讨论】:

  • 您是否有机会通过网络文件夹访问您的数据库文件?
  • 不,这是安装在手持设备上的 Windows CE 应用程序中的嵌入式 SQL Server CE 数据库。
  • 那么可能有东西锁定了它的文件。 new SqlCeConnection(SQLCE_CONN_STR) 失败了。
  • 那个 finally 块是多余的,不是吗,用 using 语句呢?
  • 问题可能出在其他仍然有连接打开的地方。将using 语句放在您的连接对象上。

标签: c# compact-framework sql-server-ce windows-ce


【解决方案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 步。

【讨论】:

  • 我已经通过复制项目中的现有代码来“重新开始”这种方法,我认为这将解决这个特定问题(项目确实使用了对其管理的连接的引用),但是有转到 that 当前导致的异常:stackoverflow.com/questions/15798207/…
【解决方案2】:

如果文件未标记为只读(您检查过,对吗?),那么您有另一个进程对该文件具有非共享锁定。

如果 SQL CE 附带的 isql.exe 数据库浏览器在后台运行,它就是一个常见的罪魁祸首。

根据您的 SQLCE 版本,很可能另一个进程有一个打开的连接(不记得是哪个版本开始允许多个进程连接),所以如果您在后台有任何其他应用程序打开它,那也可能是个问题。

您还使用了大量连接到该数据库的连接,它们并不总是被清理并立即释放到 Dispose。我强烈建议构建一个简单的连接管理器类,它保持与数据库的单个(或更多类似两个)连接,并将它们重用于所有操作。

【讨论】:

  • *.sdf 文件不是只读的。我不知道我的 SQLCE 版本,但 .NET 的版本是 1.1。我害怕对这段代码进行任何激进/重大的更改,因为它非常复杂,以至于我不明白它的原因和原因,并且可能会造成更大的混乱。我只想做最低限度的必要工作,然后离开,继续其他项目。
  • 我理解您的挫败感,但如果它现在不起作用,那么进行更改似乎是一条合理的前进道路。毫无疑问,您可以放弃大量的代码改进机会,但让它发挥作用可能是必须的。就个人而言,我已经构建了一个非 VM 开发机器,这样我就可以在到达你现在的位置之前有效地进行调试。我再说一遍,.NET 的版本不是 1.1,它是 1.0。没有 CF 1.1。
  • 事实证明,我所做的许多“改进”都不得不返回和反转(例如在查询中将“?”替换为“@”)和“.Add (""+bla, Blah)" 和 ".Add(bla, Blah)" (其中 "bla" 是一个 int 并且前面的 """" 被转换为一个字符串。错误的和过时的,看起来,但尝试使这些东西现代化在很大程度上是一种挫败感和徒劳的练习。
  • 我要在这里添加的评论太长了,所以如果你有兴趣在你的脑袋里有那种蜘蛛网的感觉,请查看我的更新。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-10-11
  • 2013-10-27
  • 2016-12-16
  • 1970-01-01
  • 2021-01-09
  • 2012-12-28
  • 2011-06-29
相关资源
最近更新 更多