2

テーブル (文字列)、列の配列 (文字列)、値の配列 (オブジェクト) をパラメーターを介して渡すことができるメソッドを開発しました。これを使用して、パラメーター化されたクエリを作成します。コードの長さと複数の for ループがコードの匂いを放っていることは問題ありませんが、特に、列と値の間にコンマを挿入するために使用する方法は、別のより良い方法で実行できると感じています。

public static int Insert(string source, string[] column, object[] values)
{
    int rowsAffected = 0;
    try
    {
        using (SQLiteConnection conn = new SQLiteConnection(connectionString))
        {
            StringBuilder query = new StringBuilder();
            query.Append(" INSERT INTO ");
            query.Append(source);
            query.Append("(");

            for (int i = 0; i < column.Length; i++)
            {
                query.Append(column[i]);

                if (i < values.Length - 1)
                {
                    query.Append(",");
                }
            }

            query.Append(")");
            query.Append(" VALUES ");
            query.Append("(");

            for (int i = 0; i < values.Length; i++)
            {
                query.Append("@" + values[i].ToString());

                if (i < values.Length - 1)
                {
                    query.Append(",");
                }
            }

            query.Append(")");

            conn.Open();
            using (SQLiteCommand cmd = new SQLiteCommand(query.ToString(), conn))
            {
                for (int i = 0; i < values.Length; i++)
                {
                    cmd.Parameters.AddWithValue("@" + values[i].ToString(), values[i]);
                }
                rowsAffected = cmd.ExecuteNonQuery();
            }
        }
        return rowsAffected;
    }
    catch (Exception e)
    {
        MessageBox.Show(e.Message);
    }
    return 0;
}

System.Data.SQLiteライブラリを使用してデータベースとやり取りしています。

ご提案ありがとうございます。

4

3 に答える 3

6

これは、StringBuilder を使用して区切り記号で複数の値を追加する私の慣用的な方法です。

string separator = ",";
for (int i = 0; i < column.Length; i++)
{
    query.Append(column[i]);
    query.Append(separator);
}
query.Length -= separator.Length;

これは、少なくとも1つの値があることを前提としています。通常、私が使用する場合、少なくとも1つの値がない場合はエラーになります(シナリオはそのようです)。

また、SQL インジェクションに対してこのコードを広く公開したようです。

パラメータを使用しようとしているようですが、正しく行ったとは思いません。私がコードを読んだ方法では、インデックスの代わりにパラメーターの実際の値を使用しています。この変更をお勧めします(これは、列名の配列が信頼できるソースからのものであることを前提としていますが、値はそうではありません):

        for (int i = 0; i < values.Length; i++)
        {
            query.Append("@" + i.ToString()); // instead of query.Append("@" + values[i].ToString());

            if (i < values.Length - 1)
            {
                query.Append(",");
            }
        }

        query.Append(")");

        conn.Open();
        using (SQLiteCommand cmd = new SQLiteCommand(query.ToString(), conn))
        {
            for (int i = 0; i < values.Length; i++)
            {
                cmd.Parameters.AddWithValue("@" + i.ToString(), values[i]); // instead of cmd.Parameters.AddWithValue("@" + values[i].ToString(), values[i]);
            }
            rowsAffected = cmd.ExecuteNonQuery();
        }
    }
于 2011-04-01T21:21:37.187 に答える
3

これが機能するには、パラメーターと値の数が常に同じである必要があるため、2 つの StringBuilder を使用してループをなくすことができます。(テストされていないコードですが、要点を理解する必要があります)

            StringBuilder query = new StringBuilder();
            StringBuilder insertParams = new StringBuilder();
            query.Append(" INSERT INTO ");
            query.Append(source);
            query.Append("(");

            for (int i = 0; i < column.Length; i++)
            {

                if (i < values.Length - 1)
                {
                    query.Append(",");
                    insertParams.Append(",");
                }
                query.Append(column[i]);
                insertParams.Append("@" + values[i].ToString());
            }

            query.Append(")");
            query.Append(" VALUES ");
            query.Append("(");
            query.Append(insertValues.ToString());
            query.Append(")");

長さが同じなので、パラメーター リストと値リストを同時に作成し、ループの最後の適切な場所に値リストを貼り付けることができます。正味の結果はより速くなるはずです。:)

于 2011-04-01T21:21:10.690 に答える
1

ここに別のオプションがあります。元のコードと同じことを実際に行っていますが、小さなチャンクに分割し、InsertBuilder というクラスに抽象化しています。

public class InsertBuilder
{
    public InsertBuilder()
    {
    }

    public InsertBuilder(string tableName, string[] columns, object[] values)
    {
        this.tableName = tableName;
        this.columns = columns;
        this.values = values;
    }

    private string tableName;
    public string TableName
    {
        get { return tableName; }
        set { tableName = value; }
    }

    private string[] columns;
    public string[] Columns
    {
        get { return columns; }
        set { columns = value; }
    }


    private object[] values;
    public object[] Values
    {
        get { return values; }
        set { values = value; }
    }

    public string InsertString
    {
        get
        {
            return CreateInsertString();
        }
    }

    public void Clear()
    {
        this.values = null;
        this.columns = null;
        this.tableName = null;
    }

    private string CreateInsertString()
    {
        if(columns.Length == 0) 
            throw new InvalidOperationException(
                "Columns must contain atleast one column"
                );

        if(values.Length == 0) 
            throw new InvalidOperationException(
                "Values must contain atleast one value"
                );

        if(columns.Length != values.Length)
        {
            throw new InvalidOperationException(
                string.Format(
                    "Columns length {0} does not match Values length {1}",
                    columns.Length,
                    values.Length)
                    );
        }

        StringBuilder insertString = new StringBuilder();

        insertString.Append(CreateTableStatement());

        insertString.Append(CreateColumnsStatement());

        insertString.Append(CreateValuesStatement());

        return insertString.ToString();

    }

    private string CreateTableStatement()
    {
        return " INSERT INTO " + tableName;
    }

    private string CreateColumnsStatement()
    {
        StringBuilder columnsStatement = new StringBuilder();

        columnsStatement.Append("(");

        for(int i = 0;i < columnsStatement.Length;i++)
        {
            columnsStatement.Append(columnsStatement[i]);
            if(i < values.Length - 1) { columnsStatement.Append(","); }
        }

        columnsStatement.Append(")");

        return columnsStatement.ToString();
    }

    private string CreateValuesStatement()
    {
        StringBuilder valuesStatement = new StringBuilder();

        valuesStatement.Append("VALUES");
        valuesStatement.Append("(");

        for(int i = 0;i < values.Length;i++)
        {
            valuesStatement.Append("@" + values[i].ToString());

            if(i < values.Length - 1) { valuesStatement.Append(","); }
        }

        valuesStatement.Append(")");

        return valuesStatement.ToString();
    }

}

次に、元のコードは次のようになります。

public static int Insert(string source, string[] column, object[] values)
{
    int rowsAffected = 0;
    try
    {
        using(SQLiteConnection conn = new SQLiteConnection(connectionString))
        {
            InsertBuilder insertBuilder = new InsertBuilder();
            insertBuilder.TableName = source;
            insertBuilder.Columns = column;
            insertBuilder.Values = values;

            using(SQLiteCommand cmd = new SQLiteCommand(insertBuilder.InsertString, conn))
            {
                for(int i = 0;i < values.Length;i++)
                {
                    cmd.Parameters.AddWithValue("@" + values[i].ToString(), values[i]);
                }

                conn.Open();

                rowsAffected = cmd.ExecuteNonQuery();
            }
        }

        return rowsAffected;
    }
    catch(Exception e)
    {
        MessageBox.Show(e.Message);
    }

    return 0;
}
于 2011-04-01T22:02:14.793 に答える