y-matsui::weblog

電子楽器、音楽、コンピュータ、プログラミング、雑感。面倒くさいオヤジの独り言

DataTableを使ってオンメモリのデータベース

■目的(用途)
・データベースを使うまでもない件数(せいぜい数千件)
・ファイルコピーだけで動作する検索アプリケーション
・更新がほとんど発生しない検索アプリケーション
・更新は一括、メンテナンスは表計算ソフトで

■方針
CSVデータの入れ替えでデータ更新を行う
・アプリケーション起動時にサーバメモリ上へデータを読み込み
・セッション内ではオンメモリのデータベースに検索を実行する
CSVをアップロードしたらメモリ上のDataTableをリロードしてデータを更新(データメンテナンスツール)

■方法
1:アプリケーションの起動時にCSVを読み込む
→global.asaxのApplication_Startで、App_Code\common.csのcsv2dtメソッドを実行
2:メソッドで得られたDataTableをApplication変数に代入する
3:view.aspx読み込み時にApplication変数内のDataTableを読み込む
4:filter式を適用してDataTableをDataViewに代入する
5:view.aspx内のDataViewにBindする

■結果
・3万件、132列、13MBのCSVをDataTableとして読み込み、検索動作OK。
※最初の読み込みがめちゃくちゃ遅いが、検索は非常に高速。

■DataTableの制限事項
・最大行数は16,777,216 行(十分だ)

<具体例>

■Global.asaxのApplication_Startイベントで実行
string csv;
System.Data.DataTable dt;
csv = common.GetConfig(キー名);
dt = common.csv2dt(Server.MapPath(csv), テーブル名);
Application.Set("dt", dt);

■App_Code\common.cs内メソッド”csv2dt”
public static DataTable csv2dt(string fname, string tablename)
{
//CSVフォーマットは、1行目にフィールド名、2行目:コメント行、3行目以降がデータ行
DataSet ds = new DataSet("データセット名");
DataTable dt;
DataRow dr;

TextFieldParser parser = new TextFieldParser(fname,
System.Text.Encoding.GetEncoding("Shift_JIS"));

using (parser)
{

parser.TextFieldType = FieldType.Delimited;
parser.SetDelimiters(","); // 区切り文字はコンマ


// parser.HasFieldsEnclosedInQuotes = false;
// parser.TrimWhiteSpace = false;

dt = ds.Tables.Add(tablename);
int i = 0;

while (!parser.EndOfData)
{
//行を読む
string[] row = parser.ReadFields(); // 1行読み込み
dr = dt.NewRow();

int j = 0;
//列を読む
foreach (string field in row)
{
//文字列の加工
string f = "";
f = field;
f = f.Replace("\r\n", "
"); // 改行を
で表示
f = f.Replace("
", "
"); // 改行を
で表示
//f = f.Replace(" ", "_"); // 空白を_で表示

if *1
{
switch (f.Substring(0, 2))
{
case "c_": //文字型の場合
dt.Columns.Add(f.ToString(), Type.GetType("System.String"));
break;
//case "d_": //日付型の場合
// dt.Columns.Add(f.ToString(), Type.GetType("System.DateTime"));
// break;
//case "n_": //数値型の場合
// dt.Columns.Add(f.ToString(), Type.GetType("System.Double"));
// break;
default: //指定されていない場合は文字型で定義
dt.Columns.Add(f.ToString(), Type.GetType("System.String"));
break;
}
}
//列値の代入
dr[j] = f;
j += 1;
}
if (i >=2 ) //3行目からデータ行として認識
{
dt.Rows.Add(dr);
}
dr = null;
i += 1;
}
}
return dt;
}
■データバインド
フォームのPage_Loadイベントで実行
//GridViewに設定
DataView dv;
String filter = "";
filter = "[フィールド名]='" + [条件] +"'";
String sort = "[並び替え列名1],[並び替え列名2]";
dv = new DataView((DataTable)Application.Get("dt"), filter, sort, DataViewRowState.CurrentRows);
this.GridView1.DataSource = dv;
this.GridView1.DataBind();
recCnt = dv.Count;
ShowResultNum(); //件数表示


//件数表示
protected void ShowResultNum()
{
if (recCnt == -1)
{
lbl_Hit.Text = "";
}
if (recCnt > 0)
{
lbl_Hit.Text = recCnt.ToString() + "件が該当しました。";
}
if (recCnt == 0)
{
lbl_Hit.Text = "0件が該当しました。";
}
if (recCnt >= 1000)
{
lbl_Hit.Text = "1000件以上は表示できません。";
}

}

*1:i == 0) && (f.Length > 2