Excel ファイルの類似検索、ひとまず公開

Excel ファイル、と言いますか、バイナリファイルの類似検索のツールです。

BinDiffCheck.0.1 からダウンロードしてください。

フォルダ内にある、ファイルを「いい感じ」に比較して、どれだけ近いか、を出すツールです。

image

  1. チェックするフォルダを指定します。
    (複数フォルダは指定できないから…あったほうがいいかな?)
  2. チェックする拡張子を指定します。
    空欄の場合は、すべてのファイルが対象になります。
  3. 「実行」すると、相互にファイルをチェックしていきます。
  4. 結果を「コピー」ボタンでクリップボードにコピーして、Excel に貼りつけてください。
  5. 「DiffFile」の値が、小さいほど似通っています。

Diff のロジックは、2007-03-15 – 当面C#と.NETな記録 からそのまま頂いております。

image

適当に、オートソートを掛ければわかりやすいかなと。

2つの Excel を比較する場合は、vector とかで、ベクター : 「excel ファイル 比較」の検索結果 すると、色々出てきます。

ソースコードの公開は、後程。

カテゴリー: ツール | Excel ファイルの類似検索、ひとまず公開 はコメントを受け付けていません

Excel ファイルの類似検索の続き

単純に2ファイルを比較する部分は、

2007-03-15 – 当面C#と.NETな記録
http://d.hatena.ne.jp/siokoshou/20070315

にある FastDiff のコードをコピーして利用。

namespace SampleBinDiff
{
	class Program
	{
		static void Main(string[] args)
		{
			string srcfile = args[0];
			string destfile = args[1];

			Program prog = new Program();
			prog.Go(srcfile, destfile);
		}

		public int Go(string srcfile, string destfile)
		{
			string src = BinToString(srcfile);
			string dest = BinToString(destfile);

			// DiffResult[] res = FastDiff.DiffChar(src, dest);
			DiffResult[] res = FastDiff.Diff(src, dest);

			Console.WriteLine("count: {0}", res.Length);
			int diffcount = 0;
			foreach (var di in res)
			{
				Console.WriteLine(di.ToString());
				if (di.Modified)
				{
					diffcount += di.ModifiedLength + di.OriginalLength;
				}
			}
			Console.WriteLine("diffcount: {0}", diffcount);
			return 0;
		}

		public string BinToString( string fname ) 
		{
			BinaryReader br = new BinaryReader(File.Open(fname, FileMode.Open,FileAccess.Read));
			byte[] data = new byte[new FileInfo(fname).Length];
			br.Close();
			StringBuilder sb = new StringBuilder();
			foreach (byte b in data)
			{
				sb.Append(Convert.ToString(b, 16));
				sb.Append("\n"); // 行単位で比較
			}
			string src = sb.ToString();
			return src;
		}
	}
}

バイナリ比較のために FastDiff.DiffChar で比較しようと思ったのだけど、あまり思ったような結果が得られないので、無理矢理改行コードを入れて FastDiff.Diff で比較しています。

実行結果は以下のような感じ。ファイル名を2つ指定すると、diffcount という数値を出します。diffcount が 0 であれば一致、大きければそれだけファイルが違うという感じ。

Debug>SampleBinDiff ..\..\Program.cs ..\..\Program3.cs
count: 2
Common, OrgStart:0, OrgLen:2720, ModStart:0, ModLen:2720
Modified, OrgStart:2720, OrgLen:0, ModStart:2720, ModLen:24
diffcount: 24

これを相互 10,000 ファイルで当たっていけばよいので、適当な閾値をつけて類似ファイルを見つけるか、ヒストグラムを出して、一致する自動的に閾値を見つけるか、という感じで。続きは明日。

カテゴリー: C# | Excel ファイルの類似検索の続き はコメントを受け付けていません

Excel ファイルの類似検索(準備)

Twitter / @futamiryo: 画像は類似検索があるけどxlsやzipは完全一致ばっ …
https://twitter.com/#!/futamiryo/status/163566455504375808

 

image

単純に、バイナリdiff を取ればよいのでは?と思ったり思わなかったりしただけど、

  • バイナリ形式で、Excel ファイルを比較するけど、ファイル数は 10,000 ファイルほどある模様。
  • なので、単純な突き合わせだと、10^10 のオーダーになって爆発しそう。

な訳で、2段階踏まないと、実運用に耐えなそう。

バイナリ形式の diff は、文字単位に diff を取ればよいので、2007-03-15 – 当面C#と.NETな記録 の .NET diff class の DiffChar を使うのがよさげ。比較するのが string なので、バイナリデータを 0xFF のアルファベットに直してから比較するのが良いでしょう。

比較ファイルの絞り込みは、

  • ファイル名の比較(おそらく、似た名前で作っているハズ)
  • ファイル長さの比較(あまり違う場合は、はずすとか)

にしておけば、10^10 のオーダーではなくなるハズです。

そして、結果の、DeffResult[] が、少ない順にまとめていけば、なんとなく新旧のファイルがあつまるはずですね。

結果は、なんらかの形でレポートすれば、よかろうと。

 

ってことで、ふたみさんの作業には間に合わいそうもないけどw、ちと、この路線で明日作ってみますか。

カテゴリー: 開発 | Excel ファイルの類似検索(準備) はコメントを受け付けていません

Excel 方眼紙を作る方法他

Tips と言いますか、メモ書き。時々忘れるので。
画像の編集とかの場合には、「Excel 方眼紙」を作ると便利です。特に Excel 2010 にもなると、ワードアートなんかを使って綺麗なロゴが作れます。ここのロゴや トニー電の.NETプログラミング講座 のロゴは Excel 2010 で作っています。

■背景が白の方眼紙を作る

1.Excel 2010 を起動して、列を CZ ぐらいまで適当に選択
2.そのまま右クリックして、「列の幅」をクリックする。

3.列の幅を「2」に設定
4.方眼紙っぽくなります。

5.リボンで「ファイル」→「オプション」をクリック
6.「詳細設定」のタブで、「枠線を表示する」のチェックを外す。

あるいは、リボンの「ページレイアウト」→「枠線」→「表示」

7.これで、背景が白の Excel シートができます。

■複数のオブジェクトを選択

貼りつけたオブジェクトを選択したい場合は、ひとつひとつ選択してもよいのですが、以前のようにマウスで囲みたいですよね。Excel 2010 の場合は、リボンの「ホーム」→「検索」の▼ボタンを押して「オブジェクトの選択」でできます。

こんな風に範囲で選択できます。

■オブジェクトをグリッドに合わせる

方眼紙なのですから、グリッドにぴったりに合わせることもできます。
何かのオブジェクトを選択した状態で、リボンの「書式」→「配置」の「枠線にあわせる」をチェックします。

こうすると、枠線(グリッド)に合わせることができるので、図形を綺麗にそろえることができます。

微妙な位置合わせは、図形を選択した状態で、カーソルキー(↑↓など)でドット単位(多分)動かせるので、これを使うとよいかも。

■図形から画像ファイルを作る、クリップボードへコピーする

Excel には面白い機能があって、セルを選択した状態にして、Ctrl+C すると、画像がコピーされます。

この状態で、Ctrl+C でコピーします。クリップボードに転送されるので、ペイントに貼りつければ、画像ファイルに保存できます。

こんなところが、私の編集スタイルですね。高価な画像ソフトを持っていないのですが、まあ最近はこれで十分かと。

カテゴリー: 雑談 | 2件のコメント

PC から iPhone 専用サイトを覗く方法(User-Agentの偽装)

端的に言えば「User-Agent」を偽装します、ということです。
User-Agent というのは、HTTP プロトコルのヘッダ部に設定してある「今、私はこのブラウザを使っています」という印ですね。サーバーのほうで、携帯電話からなのか、PC からなのか、iPhone/iPad からなのか、Android からなのか、ということが分かります。

と、云いますか、当然これは「印(ルール)」でしかなくって、WebClinet クラスなり、Firefox のプラグインを利用するすれば、簡単に自分が何者かを偽装するこができます(「詐称」という言葉を使っているところもあるけど、技術的にすり替えるだけなので「偽装」のほうがよいかなと)。

さて、なぜ iphone 専用のサイトを pc から覗く必要があるかというと、hon.jp の api を利用して amazon 風のブログパーツを作りたいからなのです。amazon ブログパーツは、書籍の画像を返してくれるのですが、hon.jp api は、画像を返してくれません。hon.jp の場合、タイトル検索などのテキスト検索が主なので、電子書籍の画像は各社のサイトの中にしかありません。pc 用の電子書籍がある場合は、pc からキャッシュ的に取得すればよいのですが、iphone 用しかない場合には、iphone 用のページにアクセスする必要があります。なので、画像を取得するためには iphone であると偽装して画像用の url を取得しないと駄目なのです。

と前置きはそれくらいにして、ざっとこんな感じ。

private void button2_Click(object sender, EventArgs e)
{
	// url を取得
	string url = textBox1.Text;
	WebClientEx client = new WebClientEx();
	// cookie を設定
	client.Cookie = new CookieContainer();
	client.Headers.Add("User-Agent", "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3_4 like Mac OS X; ja-jp) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8K2 Safari/6533.18.5");
	// sjis で全て読み込み
	StreamReader sr = new StreamReader(client.OpenRead(url), Encoding.GetEncoding("shift_jis"));
	string content = sr.ReadToEnd();
	sr.Close();
	// ファイルに出力
	StreamWriter sw = new StreamWriter("temp.html", false, Encoding.GetEncoding("shift_jis"));
	sw.Write(content);
	sw.Close();

	// ブラウザコントロールで表示
	webBrowser1.Navigate("file://" + @"D:\work\blog\src\SampleUserAgent\SampleUserAgent\bin\Debug\"+ "temp.html");
	// テキストボックスでも表示
	textBox2.Text = content;

}

文字コードが sjis になっているのは、電子文庫パブが sjis で返すからです。本来は charset を見てコードを判別しないと駄目ですね。また、電子文庫パブの場合は、cookie が必要になるのでこれも設定してます。
Cookie 自体は、内部の HttpWebRequest を弄る必要があるので、こんな風に継承したクラスを作ります(という例があった)。

class WebClientEx : WebClient
{
	public CookieContainer Cookie { get; set; }
	protected override WebRequest GetWebRequest(Uri address)
	{
		HttpWebRequest wreq = base.GetWebRequest(address) as HttpWebRequest;
		wreq.CookieContainer = this.Cookie;
		return wreq;
	}
}

実行するとこんな感じで取得できます。

画像が表示されないのは、img タグの src 相対パスになっているからです。
保存した html ファイルを開いて を追加すると、こんな感じで表示できます。

これで画像の url が分かるので、ブログパーツを表示する時に画像が表示できますね。
画像 url が変わる可能性もあるのでキャッシュしてもいいのですが、まぁ、amazon と同じで画像ファイル名はほとんど変わらないのではないかなと。これは、いくつかの電子書籍の会社を探ってから考えましょう。

■参考
userAgent一覧/ユーザーエージェント一覧
http://www.openspc2.org/userAgent/

カテゴリー: C# | PC から iPhone 専用サイトを覗く方法(User-Agentの偽装) はコメントを受け付けていません

UILabelやUIImageViewのタッチイベントを取得する

iPhone プログラミングの中で、ボタンのクリックイベントは簡単に取れるのですが、ラベルや画像のクリックイベントが手軽に取れません。いくつか調べると、UITapGestureRecognizer を使うか、touchesEnded メソッドをオーバーライドするか、という方法があるのですが手軽でもないので。

iphone – How can I determine if a UILabel was touched? – Stack Overflow
http://stackoverflow.com/questions/2539380/how-can-i-determine-if-a-uilabel-was-touched
UILabelのタッチイベントを検出する方法 ? 拡張現実ライフ
http://akio0911.net/archives/3419

どうやら、tag を使うと一番手軽そうなので紹介しておきます。

最初に、viewDidLoad の中で tag を設定しておきます。userInteractionEnabled プロパティの値を YES にしておかないとイベントが発生しなくなるので注意してください(何故イベントが発生しないのかは不明)

- (void)viewDidLoad
{
    [super viewDidLoad];
	// Do any additional setup after loading the view, typically from a nib.
    labelCommand.userInteractionEnabled = YES;
    labelCommand.tag = 100;
    imageLogo.userInteractionEnabled = YES;
    imageLogo.tag = 101;
}

「100」とか「101」とかは、適当な値で十分です(0は初期値なので駄目)。
#define しても良いのですが、使い捨てなのでそのまま。

touchesBegan イベントをオーバーライドします。ViewController 上にあるイベントをタッチイベントを全てフックするので、これから目的のオブジェクトを探し出します。

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [[event allTouches] anyObject];
    if ( touch.view.tag == labelCommand.tag )
        [self clickCommand:labelCommand];
    else if ( touch.view.tag == imageLogo.tag )
        [self clickLogo:imageLogo];
}

ここで、touch.view.tag と、ラベルの tag の値とを比較します。本来は switch で比較するのが良いのでしょうが、面倒なので(苦笑)そのまま tag の値と比較しています。実は、こうすると #define が必要なくなるのです。

イベントは、ボタンのクリックイベントのように書きたいため、ViewController 上で定義した clickCommand を呼び出します。一応、sender はラベルや画像オブジェクトそのもの渡します。

-(IBAction)clickCommand:(id)sender 
{
    NSLog(@"in clickCommand");

}
-(IBAction)clickLogo:(id)sender 
{
    NSLog(@"in clickLogo");
}

こんな風に、あたかもボタンと同じようにしておきます。こうすると、クリックイベントみたいで分かり易いですよね。

実行すると、普通のボタンと同じようにログが出力されます。

カテゴリー: Objective-C | 6件のコメント

LinqToTwitter を使う

ツイートキャッチ★★★を LINQ to Twitter を使うように書き換え中…と言いますか、なんか、LINQ to Twitter って、内部で Invoke をしているらしく、サーバーエラー時の挙動がおかしいんですよね。なので、Twitter が不安定な時の対処が難しい、というのが前置きなのですが。

とは云え、使い方は結構簡単です。LINQ を使って検索するので、検索系はOKかと。更新系はどうなのかいまいち確認してないのでツイート専用のほうは、TwiLib を使ったままなんですが。

例えば、ログインしている人のツイート数を取得するのは、こんなに簡単に書けます。twitter が返してくる xml の要素名と、linq to twitter で定義しているプロパティ名との「ずれ」が、いまいち分かりづらいのですが、慣れればなんとか。

// ツイート数を取得
var ctx = new TwitterContext(this.auth);
var user = (from t in ctx.User 
			where t.Type == UserType.Show &&
			t.ScreenName == username
			select t).First();
this.profile_image_url = user.ProfileImageUrl;
this.tweet_count = user.StatusesCount;

で、具体的に oauth 認証をどうするかというと、ツイートキャッチでは次のようにしています。

if (accessToken == "")
{
	auth = new PinAuthorizer();
	auth.Credentials = new InMemoryCredentials {
		ConsumerKey = this.consumerKey,
		ConsumerSecret = this.consumerSecret 
	};
	auth.UseCompression = false;
	auth.GoToTwitterAuthorization = link => {
		Process.Start(link);
	};
	auth.GetPin = () =>
	{
		FormAuth frm = new FormAuth();
		frm.ShowDialog();
		return frm.PinCode;
	};
	auth.Authorize();
	this.SavaAuth();
	return;
}
auth = new PinAuthorizer();
auth.Credentials = new InMemoryCredentials
{
	ConsumerKey = this.consumerKey,
	ConsumerSecret = this.consumerSecret
};
auth.OAuthTwitter.OAuthToken = this.accessToken;
auth.OAuthTwitter.OAuthTokenSecret = this.accessSecret;

oauth 認証を使う時のキーワードとして、

  • アプリケーションが使う consumerKey
  • アプリケーションが使う consumerSecret

のセットと

  • 認証後に使う accessToken
  • 認証後に使う accessSecret

の4つのキーワードがあります。

手順としては、

  1. アプリケーションを作るときに consumerKey と consumerSecret を取得(アプリに書き込む、app.configとか)
  2. ユーザーが初回実行時に consumerKey と consumerSecret を使って pincode を得る。
  3. pincode を使って、accessToken と accessSecret のセットを得る。
  4. web ならば、ユーザー名と紐づけて保持、winodws アプリならばレジストリとかに保存

  5. 次回以降は、consumerKey, consumerSecret, accessToken, accessSecret の 4つがあれば ok

という具合です。

なので、ワンクッションだけユーザーに pincode を入力して貰う必要があるのです。まぁ、これが認証ということです。勿論、内部ブラウザで表示させたりして、pincode を自動入力させることも可能ですが、手入力でも対して手間じゃないのでそのまま。

で、linq to twitter はこの pincode を入力するとこがややこしくて、下記のように GetPin にコールバックを登録させます。

	auth.GetPin = () =>
	{
		FormAuth frm = new FormAuth();
		frm.ShowDialog();
		return frm.PinCode;
	};

どうしようかと悩んだのですが、ツイートキャッチ★★★では、別のダイアログを出して対処をするようにしました。

linq は検索のほうを得意とするので、直近のツイートを取得なんてのは、こんな風に書けます。

/// <summary>
/// ツイートを取得
/// </summary>
/// <param name=&quot;sname&quot;></param>
/// <param name=&quot;max_id&quot;></param>
/// <returns></returns>
private List<Status> GetTweets(string sname, string max_id = &quot;&quot;)
{
	var ctx = new TwitterContext(this.auth);
	var items = from t in ctx.Status
				where t.Type == StatusType.User
				&& t.ScreenName == username
				&& t.Count == MAX_TWEET
				&& t.MaxID == max_id
				select t;
	var lst = items.ToList<Status>();
	return lst;
}

# MaxID はクローリングのために使っているのですが、元のソースは int 型になっているのでエラーになります。ソースを string 型に適当に直しています。現在、twitter id は intの範囲を超えてしまっているので、string で保持するのがよいでしょう。

実は、最大の難関がサーバーエラーの対処なのですが、そのままではうまく動かないので諦めました。
なので、試しに oauth 認証の部分だけ linq to twitter のコードを使って、戻されてきた xml データは自前で解析するというのを試してみました。この話しは別の記事で。

カテゴリー: C# | LinqToTwitter を使う はコメントを受け付けていません

inline php を使う

WordPress ? Inline PHP ≪ WordPress Plugins
http://wordpress.org/extend/plugins/inline-php/

先日 wordpres 上で javascript が動作するプラグインを入れたのですが、php のコードを直接動かすことも可能なのですね。
公開する場合には、うかつな php コードを入れるとセキュリティ上危ないのでお勧めできませんが、まぁ、試しにいれるのも良いかなと。

 [ exec]
 echo "テスト表示";
 [ /exec]

のように簡単に書けますということで。

で、プログインのソースコードを見ていたのですが、実は大したことはやってないのですね。数行だけなのです。なるほど、こういう風に拡張するのかという。

[exec]
function curl_get_contents( $url, $timeout = 60 ){
$ch = curl_init();
curl_setopt( $ch, CURLOPT_URL, $url );
curl_setopt( $ch, CURLOPT_HEADER, false );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ch, CURLOPT_TIMEOUT, $timeout );
$result = curl_exec( $ch );
curl_close( $ch );
return $result;
}
// アクセス解析
$result = curl_get_contents( “http://ameblo.jp/s-mitsumori/entry-11142403355.html”, 60 );
[/exec]

カテゴリー: 開発, Wordpress | inline php を使う はコメントを受け付けていません

Excel を LINQ で検索する方法

よく業務の帳票を作る時は、Excel の隠しシートを使って「印刷画面」と「データ画面」を分けて作ります。
直接帳票をデータベースから書き込んでもいいのですが、

  • セルの名前付けの不整合などがややこしい。
  • 行列を指定するときなんか、かなり大変。

ということがあって、別にデータ用のシートを用意しておいて、セル参照させるんですよね。ただ、このパターンって、行数が増えるようなレポートの場合はうまくいかなくて、結局のところコードのほう(C#/VB)で、がりがりと行列を作り込んだりします。

さて、本来はデータの書き込みを紹介したいところなのですが、OleDb プロバイダって entity data model に対応していないじゃん、ということでちょっとげんなり…どうしたものかと思っていたところ、結構簡単に linq 実装が出来そうなソースを見つけました。

Using Linq with Excel sheets
http://geekswithblogs.net/CodeSpeaker/archive/2009/10/04/using-linq-with-excel-sheets.aspx

肝は、LinqToExcelProvider クラスのところで、難ということはない、従来の OLEDB 接続をしてから、LINQ で使えるようなリスト(EnumerableRowCollection<>)を返しているだけなんですね。なるほど、これで十分です。

DataTableExtensions.AsEnumerable メソッド (System.Data)
http://msdn.microsoft.com/query/dev10.query?appId=Dev10IDEF1&l=JA-JP&k=k(SYSTEM.DATA.DATATABLEEXTENSIONS.ASENUMERABLE);k(TargetFrameworkMoniker-%22.NETFRAMEWORK%2cVERSION%3dV4.0%22);k(DevLang-CSHARP)&rd=true

DataSet/DataTable の AsEnumerable メソッドは、拡張メソッドという訳で、ver3.5 の時に追加されたものです。

練習がてら、ちょっとだけソースコードを書き換えたのが以下のコードです。

public partial class Form1 : Form
{
	public Form1()
	{
		InitializeComponent();
	}

	/// <summary>
	/// 内部クラス
	/// </summary>
	public class Book
	{
		public string ISBN { get; set; }
		public string Title { get; set; }
		public int Price { get; set; }
	}

	private void button1_Click(object sender, EventArgs e)
	{
		LinqToExcelProvider provider = new LinqToExcelProvider(@&quot;app_data\sampleData.xlsx&quot;);
		var items = from t in provider.GetWorkSheet(&quot;book&quot;)
					where t[&quot;title&quot;].ToString().IndexOf(&quot;ひと目&quot;) >= 0
					select new Book
					{
						ISBN = t[&quot;isbn&quot;].ToString(),
						Title = t[&quot;title&quot;].ToString(),
						Price = int.Parse(t[&quot;price&quot;].ToString())
					};
		foreach (var it in items)
		{
			Debug.Print(&quot;{0} {1}&quot;, it.ISBN, it.Title);
		}
		// バインドできるように List に変換
		dataGridView1.DataSource = items.ToList();

	}
}

/// <summary>
/// Provides linq querying functionality towards Excel (xls) files
/// </summary>
public class LinqToExcelProvider
{
	/// <summary>
	/// Gets or sets the Excel filename
	/// </summary>
	private string FileName { get; set; }

	/// <summary>
	/// Template connectionstring for Excel connections
	/// </summary>
	// private const string ConnectionStringTemplate = &quot;Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties=Excel 8.0;&quot;;
	/// Excel 2007 Connection String Samples - ConnectionStrings.com
	/// http://www.connectionstrings.com/excel-2007
	private const string ConnectionStringTemplate = &quot;Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\&quot;Excel 12.0 Xml;HDR=YES\&quot;;&quot;;

	/// <summary>
	/// Default constructor
	/// </summary>
	/// <param name=&quot;fileName&quot;>The Excel file to process</param>
	public LinqToExcelProvider(string fileName)
	{
		FileName = fileName;
	}

	/// <summary>
	/// Returns a worksheet as a linq-queryable enumeration
	/// </summary>
	/// <param name=&quot;sheetName&quot;>The name of the worksheet</param>
	/// <returns>An enumerable collection of the worksheet</returns>
	public IQueryable<DataRow> GetWorkSheet(string sheetName)
	{
		// Build the connectionstring
		string connectionString = string.Format(ConnectionStringTemplate, FileName);

		// Query the specified worksheet
		OleDbDataAdapter da = new OleDbDataAdapter(string.Format(&quot;SELECT * FROM [{0}$]&quot;, sheetName), connectionString);

		// Fill the dataset from the data adapter
		DataTable dt = new DataTable();
		da.Fill(dt);

		// Return the data table contents as a queryable enumeration

		return dt.AsEnumerable().AsQueryable();
	}
}

のような Excel を用意しておいて、シート名は「book」にします。

実行すると、こんな感じ

ちなみに「Microsoft.ACE.OLEDB」の「ACE」の部分は「Microsoft Access データベース エンジン」の略とのこと、以下のところでコンポーネントがダウンロードできます(って、visual studio 2010 が入っていないと入らない?)

ダウンロード詳細 Microsoft Access データベース エンジン 2010 再頒布可能コンポーネント
http://www.microsoft.com/downloads/ja-jp/details.aspx?FamilyID=c06b8369-60dd-4b64-a44b-84b371ede16d

カテゴリー: C#, データベース | Excel を LINQ で検索する方法 はコメントを受け付けていません

WebMatrix はどうやって、データベースに接続しているのか

SQL Server Compact が単体で動くのかを調べるのと同時に、ちょっと不思議だったのが WebMatrix のデータベース接続です。自動生成される Raizor のソースを見る限り LINQ で接続しているわけでもないし、どういう風に表示しているのかな、と思っていたのですが。具体的には、WebMatrix.Data.dll という WebMatrix 付属のデータアクセスコンポーネントを使っています。

webmatrix を起動して、ベーカリーのテンプレートで自動生成して、Default.cshtml を開くと、

@{
    Page.Title = &quot;Home&quot;;

    var db = Database.Open(&quot;bakery&quot;);
    var products = db.Query(&quot;SELECT * FROM PRODUCTS&quot;).ToList();
    var featured = products[new Random().Next(products.Count)];
}

<h1>Welcome to Fourth Coffee!</h1>

のようなコードがあります。
この「Database.Open」のところでデータベースへの接続、「db.Query」でクエリの実行、ってことが想像できます。
MSDN 上のヘルプはこちら、Database.Open Method (WebMatrix.Data)

■windows アプリで webmarix.data.dll を使う

ならば、web 上の webmatrix じゃなくて、windows form でも使えるのでは?と思って試しに接続してみました。

1.先のテンプレートサイトの bin フォルダにある webmatrix.data.dll を参照設定
2.app_data/bakery.sdf を windows プロジェクトにコピー

3.「using WebMatrix.Data;」を追加
4. コードを記述

string CNSTR = "app_data\\bakery";
private void button1_Click(object sender, EventArgs e)
{
	var db = Database.Open(CNSTR);
	var products = db.Query("SELECT * FROM PRODUCTS").ToList();
	dataGridView1.DataSource = products;
}

接続文字列…というか、Openメソッドに渡す string は comapct のデータファイルそのものです。実行ファイルのカレントディレクトリから参照されるようなので、”app_data\\bakery” を渡しておきます。同じフォルダにある場合は “bakery” だけでも ok です。

こうすると、さっくりと実行できます。

まあ、windows フォームなんだから LINQ to Entities を使えばよいし、SQL 文を直接記述したい場合には SqlCommand や SqlDataAdapter を使えばよいので、あまりメリットはないのですが、さっくりと接続したときには便利…かもしれませんね。

■ちなみに、webmatrix.data.dll と *.exe だけで動くのか?

と、肝心なことを。

この webmatrix.data.dll と *.exe 、*.sdf(データベースファイル)を windows 7 のコンピュータにコピーするだけで動作するのかどうか?、と試してみたのですが駄目でした。別途、「sql server compact edition」のインストールが必要になります。SQL Server の express edition を入れるよりは軽いとはいえ、インストールしないと使えないのはなぁ、という懸念が。

こうなると、データファイルをコピーするだけで動作可能(他のセッティングが不要)なのは、

  • SQLite(未検証)
  • Access

ってところですかね。XML ファイルを用意して、linq to xml で検索することも可能なのですが、ガッツリ読み込んでしまうので、でかいファイル(100MBのファイルとか)はちょっとなぁという感じがするのです。もっとも、それだけ大きくなると、access では駄目なような気もしますが。これは要検証ということで。

カテゴリー: C#, データベース | 1件のコメント