2009年2月27日金曜日

[他]フルテキスト検索(SQLServer2005以降)

SQLServer2005以降にはフルテキスト検索という機能が存在します。
SQL Server 2005 のフルテキスト検索機能 : 内部構造と強化機能について によれば、Likeで検索するより高速に処理が可能でかつ、Blob形式で保存されたWord形式の中身まで検索が可能なようです。SQLの例(上記URLの抜粋)は以下のとおり。

SELECT
     ProductModelId
    ,ProductName
FROM
    ProductModel
WHERE
    CONTAINS(CatalogDescription'" aluminum alloy "')

2009年2月23日月曜日

[.NET]Formアプリケーション画面更新(マルチスレッド)

.NET Framework1.1までは特に意識することなく実行できていましたが、.NET Framework2.0以降でWindowsFromアプリケーションをマルチスレッド処理する場合、ちょっとした注意が必要です。
対処方法は2つありあます。コードは以下のとおり。

■Invokeを使う(正統派)
/// <summary>
/// Invokeを使ったマルチスレッド処理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnInvoke_Click(object senderEventArgs e)
{

    //Threadを生成する
    Thread thread = new Thread(delegate() {
        //50回ループする
        for (int i = 0i < 50i++)
        {
            Thread.Sleep(500);
            //描画処理をinvokeする
            textBox.Invoke(new MethodInvoker(delegate() { 
                textBox.Text = i.ToString();
                textBox.Update();
            }));
        }
    });

    thread.Start();
}


しかし、旧来のシステムを移行する場合これらの対応を入れていくのは非常にメンドクサイ。別途動作確認をし、問題点のみInvokeを使って解決することを前提とすれば、フラグの制御のみでマルチスレッド化が実現できる。

■Control.CheckForIllegalCrossThreadCallsを使う(下位互換)
/// <summary>
/// CheckForIllegalCrossThreadCallsを使ったマルチスレッド処理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnNoInvoke_Click(object senderEventArgs e)
{
    //Control.CheckForIllegalCrossThreadCallsをtrueにすればInvokeとほぼ同等になる
    //Control.CheckForIllegalCrossThreadCalls = true;

    //Threadを生成する
    Thread thread = new Thread(delegate()
    {
        //50回ループする
        for (int i = 0i < 50i++)
        {
            //500ms待機してテキストを更新する
            Thread.Sleep(500);
            textBox.Text = i.ToString();
            textBox.Update();
        }

    });

    thread.Start();
}


私自身は実験していませんが、デバッグモードでは実行時にエラーとなるが、リリースモードでは実行時にエラーにならないらしいです。移行の過渡期なんだろうか。。。

2009年2月22日日曜日

[.NET]CSVデータを操作する(OleDb)

.NET FrameworkにはOleDbConnectionというクラスがあり、このクラスの接続文字列にCSVファイルをしていすることにより、CSVファイルをテーブルに見立てた入出力処理ができます。
しかし、以下のような問題が発生しています。

  • 空の状態(ヘッタのみ)からスタートするとidxが文字列型になってしまう(型の指定方法がわからない)
  • DELETEとUPDATEができない(CSVなので当然といえば。。。)


まあ、とりえあえずコードはこんな感じ。

private void button1_Click(object senderEventArgs e)
{
    //using System.Data.OleDb;
    string csvDir = @"c:\temp";
    string csvFileName = "test.csv";

    //接続文字列 
    string conString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + csvDir + 
                       ";Extended Properties=\"text;HDR=Yes;FMT=Delimited\"";

    string strSQL = "";
    int count = 0;

    using (OleDbConnection con = new OleDbConnection(conString))
    {
        con.Open();

        strSQL = "SELECT count(*) FROM " + csvFileName;
        using (OleDbCommand cmd = new OleDbCommand(strSQLcon))
        {
            //スカラー値を取得します
            object obj = cmd.ExecuteScalar();
            count = (int)obj;

            StringBuilder sb = new StringBuilder();
            sb.AppendLine("--------------------------------------");
            sb.Append("実行結果 [").Append(obj).Append("]\r\n");
            System.Diagnostics.Debug.WriteLine(sb.ToString());

        }

        strSQL = "SELECT MAX(idx) FROM " + csvFileName;
        using (OleDbCommand cmd = new OleDbCommand(strSQLcon))
        {
            //スカラー値を取得します
            object obj = cmd.ExecuteScalar();

            StringBuilder sb = new StringBuilder();
            sb.AppendLine("--------------------------------------");
            sb.Append("実行結果 [").Append(obj).Append("]\r\n");
            System.Diagnostics.Debug.WriteLine(sb.ToString());

        }

        strSQL = "INSERT INTO " + csvFileName + " values(" + count + ", 'abc', '" + DateTime.Now.ToString() + "')";
        using (OleDbCommand cmd = new OleDbCommand(strSQLcon))
        {

            //更新処理を実行します
            int result = cmd.ExecuteNonQuery();
            
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("--------------------------------------");
            sb.Append("登録件数 [").Append(result).Append("]\r\n");
            System.Diagnostics.Debug.WriteLine(sb.ToString());

        }

        //if (count > 0)
        //{
        //    strSQL = "DELETE " + csvFileName + " WHERE idx='" + count + "'";
        //    using (OleDbCommand cmd = new OleDbCommand(strSQL, con))
        //    {
        //        //更新処理を実行します
        //        int result = cmd.ExecuteNonQuery();

        //        StringBuilder sb = new StringBuilder();
        //        sb.AppendLine("--------------------------------------");
        //        sb.Append("更新件数 [").Append(result).Append("]\r\n");
        //        System.Diagnostics.Debug.WriteLine(sb.ToString());
        //    }
        //    //strSQL = "UPDATE " + csvFileName + " SET text1 = 'def' WHERE idx='" + count + "'";
        //    strSQL = "UPDATE " + csvFileName + " SET text1 = 'def'";
        //    using (OleDbCommand cmd = new OleDbCommand(strSQL, con))
        //    {
        //        //更新処理を実行します
        //        int result = cmd.ExecuteNonQuery();

        //        StringBuilder sb = new StringBuilder();
        //        sb.AppendLine("--------------------------------------");
        //        sb.Append("更新件数 [").Append(result).Append("]\r\n");
        //        System.Diagnostics.Debug.WriteLine(sb.ToString());
        //    }
        //}

        strSQL = "SELECT * FROM " + csvFileName + " WHERE idx<" + count;
        using (OleDbCommand cmd = new OleDbCommand(strSQLcon))
        using (OleDbDataReader rd = cmd.ExecuteReader())
        {
            PrintData(rd);
        }

    }

}

private void PrintData(OleDbDataReader rd)
{
    StringBuilder sb = new StringBuilder();
    //カラム名を取得し、カンマ区切りで編集します
    sb.AppendLine("--------------------------------------");
    for (int cnt = 0cnt < rd.FieldCountcnt++)
    {
        sb.Append(rd.GetName(cnt)).Append(",");
    }
    sb.Remove(sb.Length - 11);
    sb.AppendLine("");
    sb.AppendLine("--------------------------------------");

    //データを取得しカンマ区切りで編集します
    for (int row = 0rd.Read(); row++)
    {
        for (int col = 0col < rd.FieldCountcol++)
        {
            sb.Append(rd.GetValue(col)).Append(",");
        }
        sb.Remove(sb.Length - 11);
        sb.AppendLine("");
    }
    sb.AppendLine("--------------------------------------");

    System.Diagnostics.Debug.WriteLine(sb.ToString());

}
}


■実行結果

--------------------------------------
実行結果 [16]

--------------------------------------
実行結果 [15]

--------------------------------------
登録件数 [1]

--------------------------------------
idx,text1,text2
--------------------------------------
0,abc,2009/02/22 5:53:23
1,abc,2009/02/22 5:56:02
2,abc,2009/02/22 6:00:43
3,abc,2009/02/22 6:06:38
4,abc,2009/02/22 6:07:23
5,abc,2009/02/22 6:13:57
6,abc,2009/02/22 6:14:46
7,abc,2009/02/22 6:19:28
8,abc,2009/02/22 6:20:10
9,abc,2009/02/22 6:20:17
10,abc,2009/02/22 6:21:00
11,abc,2009/02/22 6:21:45
12,abc,2009/02/22 6:22:13
13,abc,2009/02/22 6:23:19
14,abc,2009/02/22 6:25:43
15,abc,2009/02/22 6:26:08
--------------------------------------


■データファイル

idx,text1,text2
0,"abc","2009/02/22 5:53:23"
1,"abc","2009/02/22 5:56:02"
2,"abc","2009/02/22 6:00:43"
3,"abc","2009/02/22 6:06:38"
4,"abc","2009/02/22 6:07:23"
5,"abc","2009/02/22 6:13:57"
6,"abc","2009/02/22 6:14:46"
7,"abc","2009/02/22 6:19:28"
8,"abc","2009/02/22 6:20:10"
9,"abc","2009/02/22 6:20:17"
10,"abc","2009/02/22 6:21:00"
11,"abc","2009/02/22 6:21:45"
12,"abc","2009/02/22 6:22:13"
13,"abc","2009/02/22 6:23:19"
14,"abc","2009/02/22 6:25:43"
15,"abc","2009/02/22 6:26:08"
16,"abc","2009/02/22 6:26:32"

2009年2月19日木曜日

[他]PDFで指定ページをひらく(Web)

WEB系のシステムでPDFの特定ページを開きたい場合、GETの引数を指定することによりページを開くことができるようです。コレをPDF Open Parameterというらしいです。
詳細は英語なのでアレですがPDFOpenParametersに詳細があります。たとえば3ページ目を開く場合、以下のようなパラメータを記載することで実現できるようです。

http://example.org/doc.pdf#page=3

[他]リファレンス(VBS,TSQL,ASP)

毎回、「ブックマークしてねぇー」といって探すリファレンスの部類です。備忘録としてメモ。

でも、URLが結構変わっちゃうんですよねぇ。

2009年2月13日金曜日

[.NET]エンコード後のバイト列の取得

今まではEncoding.GetBytes()を使っていったバイト列に落としていましたが、GetByteCountなるメソッドを今日発見しました!。備忘録としてメモ。コードはこんな感じ。

string text = "1192つくろう鎌倉幕府!!";
// バイト列にしたばあいの文字数が取れる
int byteLen = Encoding.UTF8.GetByteCount(text);

System.Diagnostics.Debug.WriteLine("文字数[" + text.Length + "] バイト数[" + byteLen + "]");


■実行結果
文字数[14] バイト数[34]

2009年2月10日火曜日

[他]オブジェクトブラウザ

先日、WSHでとあるActiveXの動作を確認しようと思ったのですが、資料も何も無く途方にくれていました。
で、とりあえずActiveXのクラス?からインタフェースを見ることのできる、オブジェクトブラウザを思い出しました。

しかし、エディタとOfficeくらいしか入っていないマシンのため、開発ツールは何もありません。
VBやVisual Studioなどの開発環境をインストールしていないとオブジェクトブラウザは。。。と思っていたら、ExcelなどのVBAの動作する環境についている。という情報があり、ExcelのVBA環境を見てみると、オブジェクトブラウザの起動ボタンがありました。

起動すると、該当のActiveXのメソッドやプロパティを見ることができました。
そのおかげで、どのようなインタフェースがあるのかということがわかり、ソレらしくプロパティを設定してやると動作しました。

いやー思い込みのせいで、わかりませんと回答するところでしたが、結果が出せてほっとしました。

2009年2月3日火曜日

[他]VS2008へのアップグレード

今日、何気にメールを見ていると、VS2008Proへのアップグレードパッケージのニュースがありました。

何が気になるかというと、このアップグレードの対象に「Visual.NET Version 2002, 2003/Visual C# 2005, 2008 (2005, 2008 Express Edition を含む) 」と記載があることです。

    Express Edition?

Express Editionって無料で使えるアレ(えぇまぁ私も使っています)ですよね?つまるところExpress Editionユーザ登録さえすれば通常パッケージの半額程度でVS2008Proが入手できることになります(要確認)。

とはいえ、市販価格で5万円くらい。。。私にはExpress Editionがお似合いです。