1

次のコードでエラーが発生します ( MessageBox.Show()catch ブロックの から取得します)。

「PopulateBla() の例外: ファイル共有違反があります。別のプロセスがファイルを使用している可能性があります [,,,,,,]

コード

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 がどこにどのように割り当てられるかによって異なります)。それでも十分でない場合、スローされた例外は、それが別のメソッドで発生したことを示しているため、疲れたバグハンターを誤解させる可能性があります (間違いなく、不注意なコピー アンド ペースト操作の犠牲者です)。

これは「コーディングホラー」に値する。わずか数行のコードで無視できるベスト プラクティスはいくつありますか?

別の例を次に示します。

string dynSQL = "SELECT * FROM purgatory WHERE vendor_item = '" + VendorItem + "' ";

if (vendor_id != "")
{
    dynSQL += "AND vendor_id = '" + vendor_id + "' ";
}

args を "?" に置き換えることで実行できますが、割り当てるパラメーターを決定するコードは、Joe Garagiola の平均的なクリートよりも 42 倍醜いものになります。

4

2 に答える 2

1

ファイルが読み取り専用としてマークされていない場合 (確認済みですよね?)、ファイルに非共有ロックを持つ別のプロセスがあります。

SQL CE に付属の isql.exe データベース ブラウザは、バックグラウンドで実行されている場合によくある原因です。

お使いの SQLCE のバージョンによっては、別のプロセスが開いている接続を持っている可能性が非常に高いため (複数のプロセス接続を許可し始めたバージョンを思い出すことができません)、バックグラウンドで開いている他のアプリがある場合、それは問題も。

また、そのデータベースへの大量の接続を使用していますが、それらは常にクリーンアップされ、すぐに解放されるとは限りません。データベースへの 1 つ (または 2 つ以上) の接続を保持し、すべての操作でそれらを再利用する単純な接続マネージャー クラスを作成することを強くお勧めします。

于 2013-04-03T18:37:03.813 に答える
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にあると思います。

于 2013-04-03T20:17:34.420 に答える