提供するサービスを量産するということ

巷で話題になっているので、メモ的に。

私はこうやってWebサービスをリリースしてきました。|ホットココア社長日記 @egachan
http://blog.livedoor.jp/ikiradio/archives/51525122.html

たった2週間でWEBサービスを6つ立ち上げる究極の方法!|ホットココア社長日記 @egachan
http://blog.livedoor.jp/ikiradio/archives/51026443.html

実は、2年前の記事を見たことがあるんですよね。

Web サービスの大量生産…というか、2週間で出来てしまうのはどうかなぁ、と思っていたのですが、2年後の記事を見れば、「量」というのは、それなりに人を圧倒します。

いや、「継続は力なり」ということで、成功ってのは、やり続けることの先にしかない、ってことです。

# 4月に会社を作ったそうなので、これから、って感じではありますが(些細ながらエールということで)

ちなみに、無料のWEBサービスを公開する理由は、会社の場合は、

  • 技術アピール、広告塔の役割
    → WEB製作の請負や、コンサルティングなどで収入を得ます。
  • 広告収入
    → PVを稼いで、他社から広告収入を得ます。
  • 有料会員サイト
    → 一部は無料、有料になって月額で収入を得ます。

作る側としては、定額の収入が得られるので、有料会員サイトが有力候補なのですが、サイト自体からは収入を得ず、広告塔として使うのもベターかなと思っています。株式会社ホットココアの場合は、広告塔のパターン(と思う)。

ちなみに、

WEBサービスが量産できるようになったのは、ここ最近の話で、5年前ぐらいからOSSの普及や、公開API、レンタルサーバーが非常に安くなった、ところがあげられます。

プログラムでもWEBサービスでも量産して、公開して、の流れが良いところは、

  • フィードバックが得られる、あるいは、フィードバックが得られない。
    → 得られないのは、「駄目」ということで、早めに切り捨てられる。
  • あれこれと、悩まずに済む、あるいは、妄想せずにすむ。
    → 取らぬ狸、にならずに済みます。
  • 技術力が付く
    → 単純に作るときの体力が付きます。経験値が上がるので、作るのが早くなります。

WEBサイトを作る、プログラミングができる人の最大の利点は、作って試せるところにあります。先の記事にもありますが「口だけではなんにも動かない」(口だけのコンサルタントになりたい場合は必須な技術なんですが)。

実際、モノを作ってみると、どれだけその素晴らしいアイデアが「無様な」ものなのかが分かります。そういう「無様な」ものってのは、人から見るとそう見える訳で、客観的な視点を得られます(精神的なダメージも大きいけど)。

まぁ、そういうものに晒されて、耐えたものが、そこそこ残る「商品」なのかな、と。

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

極めるという事を少し

ちびっと雑談レベルで。

コニカさん経由で知ったSALONさんなブログですが、

WEB系技術電脳日記
http://ameblo.jp/konica/
OC SALON POWER STATION
http://ameblo.jp/oc-salon/
J . C . A
http://ameblo.jp/duck-oc/

まだお会いしたことはないのですが、OverClock な仕事(なのかな?)をしばらく見ていて思ったことを。

オーバークロックって16MHzの頃ぐらいしか分からなくて、当時はちびっとでもクロック数を上げようとして発信器を変えたりなんぞがありました(私自身はやったことはないのですが)。最近は、2GHzとか格段に早くなったもので、昔のようにちびっと上げてる感じでは実用的には意味がないよなぁ、と思っていたものですが。

う~む。1か月ほど眺めていたのですが、なんか迫力が違う。つーか、オーバークロックという狭い範囲(失礼)でも極めていくと、世界に通用する、つーか、duck さんという世界一な方も近くにちらほら。

一般の人にはCPUとかGPUのオーバークロックなんて全然意味が無くて、全く興味のない話な訳ですが、そりゃあ、クラウドやらSiverlightやらiPhone/iPadやらのほうが、宣伝的に良いというか最新技術っぽいというか、そういう「目新しさ」があります。
が、そういう「目新しさ」とは別のところに、個人的な価値(大袈裟に言えば、個人の人生だったり、個人を巡る周辺の方々だったり)が歴然としてあるわけで。当然「目新しさ」という基準や、「社会的な宣伝」(社会的な貢献みたいなものも含めて)という基準もあろうというものですが、まぁ、それはそれ、これはこれ、なのかなぁ、と昨今思っています。

まあ、これは、私が会社を辞めているからだと思うし、自営業というスタイルだからと思うのですが。

「極める」というか、根本的に人は「自由」なところにあると思っています。「自らを由縁とす」という約仕方をすれば、最初の身の置き所が自分自身にあり、それが徐々に「不自由」になるごとに由縁の部分が外部に出てしまうという感じですね。
それで、自分の想うままにということろで、身勝手に見えたり、極めることに見えたり、はたまた破綻したりという現実があるわけですが、大衆という形のないもの、「有識者」という形のないもの、「最新技術」という拠り所がないもの、よりは、オーバークロックという一見よくわからない(いや、やっぱりよくわからんけど)もののほうが、地に足が付いているように見えるのが不思議なところです。

と、当たり前のことを考えてみました。

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

WindowsからMacへssh接続する

基本は、Windowsからmac mini へ VNC 接続するんだけど、やっぱりコマンドラインがいいかな、と。

VNC接続ができていると、既にmac側で「リモート接続」が有効になっているので、teraterm で ssh がつながるはずなのだが、うまくつながらない … かと思ったら、こんな落とし穴が。

普通は TeraTerm を起動して、SSH で接続。

20100902_01.jpg

ユーザ名とパスワードを入力すればOKなはずなんですが…

20100902_02.jpg

何故か、時間が経った後に、エラーになってしまう。

20100902_03.jpg

で、色々探したものの、他の人はつながるみたいなんですよね。。。

何故、私の mac mini (mac os x 10.6.4)で繋がらないのかぁ、と思っていたのすが、試しに

「チャレンジレスポンス認証」でやると、あっさり

20100902_04.jpg

暫く経つと、パスワードを入れてる画面が出ます。

20100902_05.jpg

そして接続と。

20100902_06.jpg

何故、デフォルトがチャレンジレスポンスなのか分かりませんが、ひとまずこれでつながりました。

ので、めでたしめでたし。

■参考サイト

macにsshdを設定してみた – webとかmacとかいろいろ技術メモ
http://d.hatena.ne.jp/dice-t/20071115/1195187150

 

 

カテゴリー: 開発 | WindowsからMacへssh接続する はコメントを受け付けていません

役所風にEnterキーで次のテキストボックスへ移動

先日、子供の出生届に行ってきたわけですが、まだまだ古いパソコンを使っていましたお役所さん。出生届もインターネット越しでもいいんじゃない?と思ったり、思わなかったりしたのですが、ひょいと、パソコンの画面を見ると懐かしのDOS画面でありました。

役所関係や事務関係では、まだまだ強いですよね、この手のインターフェース。

そんな訳で「タブキーで次のフォーカスに移ればいいじゃん」と思っても「エンターキー(Enter Key)で次のフォーカスに移りたい」訳で、そこには、Silverlight とか、WPF とか、WEB やら jQuery やらの話は出てきません。ひたすら、今の業務にそろえたい訳です。

という訳で、UXってのが「ユーザー体験」ならば、かつてのDOS画面風を再現させたっていいじゃないと思いついたのがこの画面。

<001>

20100901_08.jpg

って、バックを「黒」にして、文字を「緑」にしただけなんですが、もうちょっと工夫が必要ですよね。

  • MS ゴシックのフォントでは字がつぶれるので、もっと適切な固定ピッチフォントで。
  • アルファベット&数字が、きれい過ぎる感じがするので、そのあたりも。

とか。

で、真っ先に実装したいのが Enter キーによるフォーカス移動です。
Enter キーのフォーカス移動は、落とし穴が多くって、少なくとも、

・複数行のテキストボックスが入ると破綻する。
・漢字の確定の Enter キーと、アルファベットの入力途中の Enter キーを区別する。
・1行のテキストボックスだと、Enter キーでビープ音が鳴る仕様。

があります。

複数行のテキストボックスの場合は、かつての画面ってこのパターンはなかったんですよ、考えてみれば。DOSで業務画面を作る場合は、テキストのスクロールとかもなくて、大抵の場合、複数行の入力なんてのもありません。

となれば、ちょっと、業務画面チックに Enter キーを変えていくのも良いかと。

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

#if true
            // ひとつずつ登録する場合
            ekm = new EnterKeyManager();
            ekm.ProcessTabKeyEvent += new EnterKeyManager.EnterKeyEventHandler(ekm_SampleEvent);
            ekm.Add(textBox1);
            ekm.Add(textBox2);
            ekm.Add(textBox3);
            ekm.Add(textBox4);
            ekm.Add(textBox5);
            ekm.Add(textBox6);
            ekm.Add(textBox7);
            ekm.Add(button1);
#else
            // 全てのコントロールを登録する場合
            ekm = new EnterKeyManager();
            ekm.ProcessTabKeyEvent += new EnterKeyManager.EnterKeyEventHandler(ekm_SampleEvent);
            ekm.SetForm(this);
#endif

        }

        // Enterキーの制御クラス
        EnterKeyManager ekm;
        // タブ移動のイベント
        void ekm_SampleEvent(object sender, bool b)
        {
            this.ProcessTabKey(b);
        }
    }

    /// <summary>
    /// Enterキーで移動させるためのクラス
    /// </summary>
    public class EnterKeyManager
    {
        private List<Control> m_lst = new List<Control>();
        private bool imeEnter = false;

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public EnterKeyManager()
        {
        }

        // テキストボックスを追加
        public void Add(TextBox ctrl)
        {
            ctrl.PreviewKeyDown += new PreviewKeyDownEventHandler(ctrl_PreviewKeyDown);
            ctrl.KeyUp += new KeyEventHandler(ctrl_KeyUp);
            ctrl.KeyPress += new KeyPressEventHandler(ctrl_KeyPress);
            m_lst.Add(ctrl);
        }
        // テキスト以外を追加
        public void Add(Control ctrl)
        {
            ctrl.KeyUp += new KeyEventHandler(ctrl_KeyUp);
            m_lst.Add(ctrl);
        }

        // テキストボックスでEnterを押した時、BEEPが鳴るのを防ぐ
        void ctrl_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == (char)Keys.Enter)
            {
                e.Handled = true;
            }
        }

        // タブキー移動のハンドラ
        public delegate void EnterKeyEventHandler(object sender, bool b);
        // Declare the event.
        public event EnterKeyEventHandler ProcessTabKeyEvent;

        // Enterキーの処理
        void ctrl_KeyUp(object sender, KeyEventArgs e)
        {
            if (ProcessTabKeyEvent == null)
                return;

            if (e.KeyCode == Keys.Enter)
            {
                TextBox t = sender as TextBox;
                if (t == null)
                {
                    ProcessTabKeyEvent(sender, !e.Shift);
                }
                else
                {
                    if (e.Shift)
                    {
                        ProcessTabKeyEvent(sender, !e.Shift);
                        e.Handled = true;
                    }
                    else
                    {

                        if (imeEnter == true)
                        {
                            ProcessTabKeyEvent(sender, !e.Shift);
                            e.Handled = true;
                        }
                        imeEnter = false;
                    }
                }
            }
        }
        // 日本語の変換確定のEnterを区別する処理
        private void ctrl_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
        {
            TextBox t = sender as TextBox;
            if (t != null)
            {
                if (e.KeyData == Keys.Enter)
                {
                    imeEnter = true;
                }
            }
        }

        // フォームから全てのコントロールを設定する
        public void SetForm( Form frm )
        {
            foreach (Control c in frm.Controls)
            {
                TextBox t = c as TextBox;
                if (t != null)
                {
                    this.Add(t);
                }
                else
                {
                    this.Add(c);
                }
            }
        }
    }
}

EnterKeyManager クラスってのを作ってしまいます。
このクラスに、Enter キーで移動したいコントロールを Add メソッドで登録していくか、面倒な場合は Form そのものを渡してしまうか。

ひとずつ登録する場合は

            ekm = new EnterKeyManager();
            ekm.ProcessTabKeyEvent += new EnterKeyManager.EnterKeyEventHandler(ekm_SampleEvent);
            ekm.Add(textBox1);
            ekm.Add(textBox2);
            ekm.Add(textBox3);
            ekm.Add(textBox4);
            ekm.Add(textBox5);
            ekm.Add(textBox6);
            ekm.Add(textBox7);
            ekm.Add(button1);

フォームにあるコントロールを一括で登録する場合は

            ekm = new EnterKeyManager();
            ekm.ProcessTabKeyEvent += new EnterKeyManager.EnterKeyEventHandler(ekm_SampleEvent);
            ekm.SetForm(this);

イベントで、ProcessTabKeyEvent を登録しているのは、フォーカス移動のメソッド ProcessTabKey を呼び出すためなんですね。ProcessTabKey メソッドが protected になっているので、こんな風にしています。
リフレクションを使えば EnterKeyManager クラスに抑え込むことができるかもしれませんが、まあ、ひとまず。

        // Enterキーの制御クラス
        EnterKeyManager ekm;
        // タブ移動のイベント
        void ekm_SampleEvent(object sender, bool b)
        {
            this.ProcessTabKey(b);
        }

な感じで、イベントを受けたら呼び出してくださいということで。

エンターキーのフォーカス移動では、漢字の変換を確定したときの Enter キーと区別するのが結構面倒なので、晒しておきます。

電話番号入力とか、数字のみとか、フォントを固定ピッチにしてよりDOSらしくとか、ちょっと作ってみようかな、と思案中です。

■参考サイト

Enterキーを押した時に、まるでTabキーを押した時のように、次のコントロールにフォーカスを移す: .NET Tips: C#, VB.NET, Visual Studio
http://dobon.net/vb/dotnet/control/enterliketab.html#section1

全ては時の中に… : 【VB.NET】Enterキーで次のコントロールにフォーカスを移す
http://blog.livedoor.jp/akf0/archives/51318097.html#

@IT:.NET TIPS Windowsアプリケーションで[Enter]キーによるフォーカス移動を行うには? – C# VB.NET Windowsフォーム
http://www.atmarkit.co.jp/fdotnet/dotnettips/231winentermove/winentermove.html

単一行テキストボックスでEnterやEscapeキーを押した時にビープ音が鳴らないようにする: .NET Tips: C#, VB.NET, Visual Studio
http://dobon.net/vb/dotnet/control/tbsuppressbeep.html

カテゴリー: 開発 | 2件のコメント

.NET(C#/VB)で、アプリ設定を読み書き

従来、Windowsアプリケーションの設定は、レジストリを使ったり、*.iniファイルを使ったりしていたわけですが、最近は、xml が主流です。と言いますか、レジストリだったり xml だったりアプリケーション毎にばらばらです。

そんなモノだから、設定関係で誤射しそうな方も出て来ます。

なので、少し裏技ちっくですが、手軽にxmlから読み書きする方法を晒しておきます。

最初に画面はこんな感じ。

<001>

20100901_03.jpg

右のグリッドは、プロパティグリッド(PropertyGrid)と言ってお手軽にクラスのプロパティを変更できるものです。Visual Studio でも使われていて、この手の変更にぴったりなのです。

そんな感じで、xmlアクセスはこんな感じ。

using System.IO;
using System.Xml.Serialization;

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

        // 初期値
        setting = new MySetting();
        this.propertyGrid1.SelectedObject = setting;
    }

    // アプリケーションの設定
    MySetting setting;

    // 保存
    private void button1_Click(object sender, EventArgs e)
    {
        setting.Save(“setring.xml”);
    }
    // 読み込み
    private void button2_Click(object sender, EventArgs e)
    {
        setting = setting.Load(“setring.xml”);
        // プロパティグリッドに再設定
        this.propertyGrid1.SelectedObject = setting;
    }
}
   
/// <summary>
/// 設定用のクラス
/// </summary>
public class MySetting
{
    // 設定を保存
    public void Save(string filename)
    {
        XmlSerializer xs = new XmlSerializer(this.GetType());
        FileStream fs = new FileStream( filename, FileMode.Create );
        xs.Serialize(fs, this);
    }
    // 設定を読み込み
    public MySetting Load(string filename)
    {
        XmlSerializer xs = new XmlSerializer(this.GetType());
        try
        {
            FileStream fs = new FileStream(filename, FileMode.Open);
            MySetting me = (MySetting)xs.Deserialize(fs);
            return me;
        }
        catch
        {
            // 最初の場合は初期値
            return new MySetting();
        }
    }
    // 以下 public で設定を羅列

    // 数値
    public int X { get; set; }
    public int Y { get; set; }
    // 文字列
    public string Version { get; set; }
    // 構造体
    public Point XY { get; set; }
    // 更新日時
    public DateTime UpdateDate { get; set; }
}

設定用のクラス(MySetting)を作っておきます。
設定の保存は、Saveメソッドで、シリアライズで出力。
設定の読み込みは、Loadメソッドで、シリアライズで入力。

設定自体は、public プロパティを作っておきて、何処からもアクセスできるようにします。こういう風に、構造体も使えるので結構便利。

シリアライズされたXMLファイルはこんな感じ

<?xml version=”1.0″?>
<MySetting xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:xsd=”http://www.w3.org/2001/XMLSchema“>
  <X>100</X>
  <Y>200</Y>
  <Version>1.0.0</Version>
  <XY>
    <X>10</X>
    <Y>20</Y>
  </XY>
  <UpdateDate>2010-09-01T11:46:30</UpdateDate>
</MySetting>

このファイルを手書きで書き換えることもできるので、お手軽の設定の変更ができます。

参照先はこちら

@IT:.NET TIPS PropertyGridコントロールを利用するには? – C# VB.NET Windowsフォーム
http://www.atmarkit.co.jp/fdotnet/dotnettips/285propertygrid/propertygrid.html

PropertyGridコントロールの使い方: .NET Tips: C#, VB.NET, Visual Studio
http://dobon.net/vb/dotnet/control/propertygrid.html#use

オブジェクトの内容をXMLファイルに保存、復元する: .NET Tips: C#, VB.NET, Visual Studio
http://dobon.net/vb/dotnet/file/xmlserializer.html

 

カテゴリー: 開発 | 3件のコメント

DataSetを使ってMySQLを扱う場合の勘所

タイトルに「MySQL」とありますが、旧来のDataSet/DataTableを使う場合のコツ、と思ってください。
# SQL to LINQ や ADO.NET Entity Framework を使う場合は、もうちょっと別なスタイルもありです。

業務アプリケーションでデータベースを扱う場合、利用方法は次のパターンに分けられます。

<001>

20100831_04.jpg 

データベースは次の2種類

・更新系のテーブル
 → 頻繁に更新するデータ
 → 売上データ、月次データなど
・マスター系のテーブル
 → ほとんど更新しないデータ
 → 部門情報、会社名一覧など

これを操作する画面が次の2種類

・一般の画面
 → 主に更新用のテーブルを扱う画面
 → 一般ユーザーが使うので、利用しやすい画面にしないと駄目
・マスタ画面
 → 主にマスタ系のテーブルを扱う
 → 保守に利用するためなので、チープ画面でよい。SEが使う。

これで、DataSetを直接扱うと良いのが、図のなかで「D」(DataSet)となっているところです。

・一般画面から更新系DBへ
 → キャッシュとして、DataSetに保持しておく。
 → 部門の一覧をコンボボックスで表示とか。
・マスタ画面からマスタ系DBへ
 → グリッドやリストなどの自動バインド(DataSource)にDataSetを直接指定。
 → DataSetの内容を直接マスタに書き込んでしまう。

一般画面から更新系DBへの矢印は、SqlCommandを使ってちまちまと更新します。
ちまちま更新は、ストアドプロシージャにしてもOK。しなくてもOK。パラメータは必須(にすると良い)。

このパターンを、MVCに当てはめると(というか、ベースがMVCなのです。このパターン/考え方は2000年頃から使っている)、

<002>

20100831_01.jpg

画面のほうは、いわずもがなの「View」、
参照系のキャッシュ部分は、「Model」、
更新系は直接データベースを扱う(SqlCommandで)ので「Controller」に相当します。

デスクトップ系のアプリケーションを作る場合、VB6(.NETにあらず)の頃は、このデータベースを扱う部分がViewに分散してしまうので、実際の開発(多人数の開発)では、もうひと工夫必要です。

開発プロジェクトの特性として、全てベテランプログラマで揃えらえることはまれです。というか、オープンソースのプロジェクトぐらいしかないでしょう。業務の場合は必ず「新人」と「ベテラン(中堅)」がいます。
そうすると、新人と中堅の技術差があります。あって当然です。

なので、この技術差をうまく活かすために、次のように配置をします。

<003>

20100831_03.jpg

新人は画面側を担当します。これは、新人の弾くスキルでは、画面、SQLなどの両方をこなすのが難しいという点。長期に続いていたプロジェクトだと、データベース周りは既に社内にいる人間しかわからないという状態になっているので覚えることが多すぎるので、できるだけデータベースから遠くに置くためです。
なので、中堅、ベテランは、新人がデータベースを扱えるように「DAO(Data Access Object)」を作ります。このDAOは、O/Rマッピングでも良いし、単なる関数呼び出しでもよいし、手順書でも良いのです。役目としては「新人をデータベースから遠くに置く」ためです。新人は「データベース」を扱いたいのではなく、「データ」を扱いたいのですから。

DAO(Data Access Object)の利点は、このほかにも、

・開発中のデータベース構造が変わっても、DAOが吸収できる(可能性がある)。
・ワンクッションあるので、実行ログがとりやすい。
・ViewにデータアクセスのSQL文が分散するのを防ぐ。

というものがあります。

一例としては、

class DAO会計情報
{
 // マスターデータの参照として使う
 // 直接使えるように公開してしまう
 public DataTable ds部署一覧;
 public DataTable ds会社一覧;
 public DataTable ds取引先一覧;

 // 更新系はメソッドを用意する。
 public bool Update月次( … );
 public bool Update日報( … );
 // 情報を取得する場合とか
 public DataTable Get月次一覧( string 個人名 );
}

のようなクラスを用意しておいて、新人には、


list部署一覧.DataSource = 会計情報.ds部署一覧
list会社一覧.DataSource = 会計情報.ds会社一覧
dv取引先.DataSource = 会計情報.ds取引先一覧

で画面を設定させて、保存ボタンを押したときに、

if ( 会計情報.Update月次( … ) == false )
{
 // 何か失敗したので、エラーメッセージ
 return ;
}
// 更新に成功した


な感じで使って貰う、という形です。

適宜、DAOの種類は増やしてください。トランザクション系もDAOに押し込めると、画面からトランザクションを意識しなくてよくなるので便利です。

Update等の戻り値は、本来は例外がいいのでしょうが、bool値とかにするほうが経験的に間違いが少なくなります。新人の「慣れ」によって適宜作ると良いかと。

このDAOの使い方をするとですね、実はテストがしやすいのです。
DAO自体に実行ログを入れるのもそうですが、うまく作ってやるとテストデータをDAOに直接読み込ませることができます。
また、単体でDAOのテストが可能になるので(MVCの良い特徴として)、NUnitなどのUnitTestが使えます。

ええと、一応、欠点も書き並べておくと、こんな感じです。

・テーブルを変更した場合、DAOも書き換わるので、手間が掛かる。
 → 各画面にSQLが散らなくていいけど、DAOが一手に引き受けるので。
・画面系が早く終わって、DAOが出来ていないとテストができない。
 あるいは、DAOのインターフェースを決めないと、画面が作れない。
 → ひとまず、インターフェースだけ先に作って、仮ビルドしてリリースします。
 → なので、DAOを使う場合は、設計が勝負どころです。
・画面が複数社に分かれる時は、DAOが使いづらい。
 → DAOを作成専門の会社/人がいればいいのですが、請負で数社に分かれると大抵破綻します。
 → なので、「身を守るために」自社だけこっそりDAO形式を使う、というのがベターです。

先日のドットネットラボの懇親会でも愚痴りましたが、理想的には「DBA(データベース管理者)」が、データベースアクセス周りを作ればよいのですが、現実問題として日本のソフトウェア業界では無理です。大規模システムの場合、元請け会社がデータベース周りを扱うことが多く、画面やその他の割り振りを子会社/孫会社に振ります。なので、データベース周り(本来DAOの部分)と画面系の部分が、会社/契約として分離されてしまうため、「大手の新人SEがDBA」を担当するという事態が発生しますし、請負→発注元という要求の通りにくいラインが邪魔をしてしまいます。
という訳で、「DBA」を前提としているデータベース技術はちょっと疑問なのですなぁ、と。

ま、それは兎も角、現実的なラインを探さないといけないわけで、最近では、幸いなことにデータベース構造までも丸投げする場合が多いし、MySQLを使った小規模の開発ならば、この手法が使えます。
ので、お試しあれ。

カテゴリー: 開発, MySQL | 2件のコメント

VNCViewerでMacに繋ぐと109キーボードが使えない

mac mini を使い始めたのだが、Windows から VNC Viewer 経由で mac を使っているせいか、109キーボードをきちんと認識しない。何故か、USキーボード(ASCIIキーボード?)に誤認されるようだ。

ネットを見た感じでは、解決できないらしい。

VNC 使用時のキーレイアウト|Mac mini でリビングPC
http://ameblo.jp/macmini/entry-10000922847.html

SE奮闘記: WindowsからMacにVNCで接続すると「=」と「’」が入力できない
http://se-suganuma.blogspot.com/2009/11/windowsmacvnc.html

上の記事にある通り、押せないキーは

「=」(イコール)、「’」(シングルクォート)、「`」(バッククォート)。

直接、キーボードを繋げればいいんだが、Windows をメインに使っている者としてはちと不便なので、調べてみると、

Ukelele

20100830_05.jpg

を使うと、キーボードのバインドを変更できる。

mac の場合は、キーバインドが、

システムの場合 /Library/Keyboard Layouts

個人ごと ~/Library/Keyboard Layouts

に *.keylayout というファイルで保存すると、そのキーバインドが「ことえり」で使える。

そんな訳で、Ukelele を使ってキーコードを頼りに変えようとしたのだが、残念ながら、何処か変なところでキーコードを変えているらしく、「”」と「’」のどちらも「”」のキーコード 39 に割り当てられていて、区別が付かず。

# 仕組み的には、中身は unix だから keyboard map があるんだけど、どれだっけ?

半日ほど色々やったのだが、面倒なので、10キーのほうに割り当てていしまうことに決めた。

20100830_03.jpg

20100830_04.jpg

10キーの「/」の位置に「’」(シングルクォート)と「`」(バッククォート)を割り当ててしまう。

あと、「=」は、キーバインドが間違っている(?)ので、直した。

このファイルは、JapanJIS.keylayout に置くので右クリック(ってできたっけ?)などでダウンロードして使って下さい。

ちなみに、109キーボードを VNCViewer 経由でつなげた時のレイアウトなので、直接109キーボードを繋げたときはどうなるのか試してはいません。

このファイルを、~/Library/Keyboard Layouts のフォルダに置いて、ことえりで「環境設定を表示」→「英字入力時のキーボード配列」で「109.JIS」を選択すると使えます。

20100830_06.jpg

あと、109キーボードを使っていて、困るのが「ことえり」で漢字モードに入って、英語モードに戻れないこと。

Ctrl+Shift+j で漢字モードに入るのだが、Ctrl+Shift+; で抜けられない。「;」のキーでShiftを押すと「+」になってしまうため。

なので、Alt + Space で漢字と英数字を切り替えるのがベター、というか、それしかできない。

ひとまず、これでプログラミングができそうだ。

 

カテゴリー: ツール | 2件のコメント

C#からMySQLを扱う(更新編)

C#からMySQLを扱う(更新編)

射撃しながら前進(あるいは迷走)する方への援護射撃。第2弾です。

MySQLでも、SQL Serverでも、Oracleでも、データをグリッドで表示する場合は、DataSetを使うのが断然楽です。
顧客が、グリッドのチープな画面を許容してくださるならば、グリッドでOKでしょう。

// コネクション作成
MySqlConnection cn = new MySqlConnection(
 "Data Source=localhost;Database=konicadb;User ID=konica;password=konica");
MySqlDataAdapter da = new MySqlDataAdapter(
 "SELECT * FROM sample", cn);
DataTable dt = new DataTable();
// 検索
da.Fill(dt);
// 表示
dataGridView1.DataSource = dt;

こんな風に、DataTable を使って書けます。

 

ちなみに、DataSet で書く場合は、

// コネクション作成
MySqlConnection cn = new MySqlConnection(
 "Data Source=localhost;Database=konicadb;User ID=konica;password=konica");
MySqlDataAdapter da = new MySqlDataAdapter(
 "SELECT * FROM sample", cn);
DataSet ds = new DataSet();
// 検索
da.Fill(ds);
// 表示
dataGridView1.DataSource = ds;

何が違うかというと(これも歴史的な話になるのですが)、もともと、DataSetは、複数のテーブルを扱える設計になっています。なので、DataSetは複数のテーブルを扱うのですが、普通は上の例のように、ひとつのテーブル(検索結果)しか扱いません。
なので、

dataGridView1.DataSource = ds;

とした場合は、最初のテーブルを使う、という仕様になっているんですね。
これが、ADO.NET のバージョンで DataTable ってのが出てきました。所詮、ひとつのテーブルしか扱わないのですから、DataSetの部分は無駄、という考えです。
なので、DataSetとDataTableは、同じように扱って大丈夫です。

 

ちなみに、DataSetから最初のテーブルを取り出す場合は、

dataGridView1.DataSource = ds.Tables[0];

と書きます。

 

余談ですが、DataSetに複数のテーブルを使う場合は、

MySqlDataAdapter da = new MySqlDataAdapter(
 "SELECT * FROM person;" +
    "SELECT * FROM company", cn);
DataSet ds = new DataSet();
// 検索
da.Fill(ds);

のように、データアダプタに対して、SQL文を二つ書きます。これは、SQL Server のみ使える機能です。
# つまりは、このために DataSet は複数のテーブルを扱えるようになっているわけです。

 

■データを追加 INSERT

データを追加するINSERT文は、通常はMySqlCommandクラスを使います。
この場合、素直にMySqlCommandクラスを使ったのが次の例です。

MySqlConnection cn = new MySqlConnection(
        "Data Source=localhost;Database=konicadb;User ID=konica;password=konica");
// コマンドを作成
MySqlCommand cmd =
    new MySqlCommand("insert into sample values (10,'konica',null,null)", cn);
// オープン
cmd.Connection.Open();
// 実行
cmd.ExecuteNonQuery();
// クローズ
cmd.Connection.Close();

SELECTの場合と違うのは、コネクションのオープンとクローズを前後に入れないと駄目なところですね。
実は、このオープン&クローズはデータアダプタが担っているのです。
データアダプタを使って INSERT 文を実行する場合は、こんな風になります。


MySqlConnection cn = new MySqlConnection(
        "Data Source=localhost;Database=konicadb;User ID=konica;password=konica");
// コマンドを作成
MySqlDataAdapter da =
    new MySqlDataAdapter("insert into sample values (11,'konica',null,null)", cn);
// データテーブル
DataTable dt = new DataTable();
// 実行
da.Fill(dt);
// 結果は無視

SELECT文とは違って、Fillメソッドで呼び出した後の結果は無視します。

 

さて、このままSQL文を書いてもいいのですが、各データを書くのが非常に面倒です。
で、よくやるパターンは、stringクラスのFormatメソッドが使われます。

MySqlCommand cmd =
    new MySqlCommand(
    string.Format("insert into sample values ({0},'{1}',{2},{3})",
        id, name, url, date));

変数を使って、整形をするパターンですが、これには重大な欠点があります。

 

・文字列の場合は「’」を使って囲まないといけない。忘れるとエラーになる。
・nullが指定できない。
・SQLインジェクションが発生する。

SQLインジェクションの問題もそうですが、文字列を意識しないといけなかったり、nullが指定できないのは致命的です。なにより、日付型(DateTime型)の指定が非常に困難です。

なので、MySqlCommandクラスでパラメータを指定するのがベターです。

MySqlConnection cn = new MySqlConnection(
        "Data Source=localhost;Database=konicadb;User ID=konica;password=konica");
// コマンドを作成
MySqlCommand cmd =
    new MySqlCommand("insert into sample values (@id, @name, @url, @date )", cn);
// パラメータ設定
cmd.Parameters.Add(
    new MySqlParameter("id", 13));
cmd.Parameters.Add(
    new MySqlParameter("name", "konica"));
cmd.Parameters.Add(
    new MySqlParameter("url", null));
cmd.Parameters.Add(
    new MySqlParameter("date", DateTime.Now));

// オープン
cmd.Connection.Open();
// 実行
cmd.ExecuteNonQuery();
// クローズ
cmd.Connection.Close();

MySqlCommandクラスでSQL文を指定する時に、「@name」のようにパラメータを指定して、MySqlParameterオブジェクトで値を指定します。

 

このようにパラメータを使うと、先の3点が一遍に解決できますし、さらに、日付型のようなちょっと指定の難しい型も簡単に設定できます。

# 本来は、ストアドプロシージャを使うのが筋なのですが、SQL文の埋め込みとストアドプロシージャは「配置」が異なるので、一概に交換できるとは言えません。なので、プロジェクトごとに、SQL文の埋め込みにするか、ストアドプロシージャにするかを考える必要があります。

■データを追加で自動採番のIDを使う場合

さて、INSERT文は書けるようになりましたが、自動でIDを振っているときはどうするのか、が問題です。
これは普通に次のように書きます。

MySqlConnection cn = new MySqlConnection(
        "Data Source=localhost;Database=konicadb;User ID=konica;password=konica");
// コマンドを作成
MySqlCommand cmd =
    new MySqlCommand("insert into sample ( name, url, date ) values ( @name, @url, @date )", cn);
// パラメータ設定
cmd.Parameters.Add(
    new MySqlParameter("id", 13));
cmd.Parameters.Add(
    new MySqlParameter("name", "konica"));
cmd.Parameters.Add(
    new MySqlParameter("url", null));
cmd.Parameters.Add(
    new MySqlParameter("date", DateTime.Now));

// オープン
cmd.Connection.Open();
// 実行
cmd.ExecuteNonQuery();
// クローズ
cmd.Connection.Close();

INSERT文で列名を指定するパターンですね。

 

ただし、ここで問題があります。このINSERTをした後でIDを取得したいときってありますよね。この場合はどうするのでしょうか?
これは、最終に更新したIDを取得するクエリを叩きます。

MySQLの場合は、「SELECT LAST_INSERT_ID()」を使うので、

MySqlConnection cn = new MySqlConnection(
        "Data Source=localhost;Database=konicadb;User ID=konica;password=konica");
// コマンドを作成
MySqlCommand cmd =
    new MySqlCommand("insert into sample (name, url, updatedate) values (@name, @url, @date)", cn);
// パラメータ設定
cmd.Parameters.Add(
    new MySqlParameter("name", "konica"));
cmd.Parameters.Add(
    new MySqlParameter("url", null));
cmd.Parameters.Add(
    new MySqlParameter("date", DateTime.Now));
MySqlCommand cmd2 =
    new MySqlCommand("SELECT LAST_INSERT_ID()", cn);

// オープン
cmd.Connection.Open();
// 実行
cmd.ExecuteNonQuery();
// 更新IDを取得
var id = cmd2.ExecuteScalar();
// クローズ
cmd.Connection.Close();

MessageBox.Show(“更新ID:” + id);

 

のように動かせば、最後に更新したIDを取得できます。
ExecuteScalarメソッドは、long型を返すのですが、キャストが面倒なのでvar型で受け取ってOKです。

■INSERT時の例外はどうするのか?

INSERT時に型チェックやIDの採番などでエラーが発生する場合があります。
これは、普通にC#の例外処理(try-catch)を入れてやれば取得できます。

MySqlConnection cn = new MySqlConnection(
        "Data Source=localhost;Database=konicadb;User ID=konica;password=konica");
// コマンドを作成
MySqlCommand cmd =
    new MySqlCommand("insert into sample (name, url, updatedate) values (@name, @url, @date)", cn);
// パラメータ設定
cmd.Parameters.Add(
    new MySqlParameter("name", "konica"));
cmd.Parameters.Add(
    new MySqlParameter("url", null));
cmd.Parameters.Add(
    new MySqlParameter("date", DateTime.Now));
MySqlCommand cmd2 =
    new MySqlCommand("SELECT LAST_INSERT_ID()", cn);
try
{
    // オープン
    cmd.Connection.Open();
    // 実行
    cmd.ExecuteNonQuery();
    // 更新IDを取得
    var id = cmd2.ExecuteScalar();
    // クローズ
    cmd.Connection.Close();
}
catch (SqlException ex)
{
    // 例外処理
    MessageBox.Show("例外発生:" + ex.Message);
}

■データを削除 DELETE

 

削除も同じように書けます。

int id = 15; // 削除するID

MySqlConnection cn = new MySqlConnection(
        "Data Source=localhost;Database=konicadb;User ID=konica;password=konica");
// コマンドを作成
MySqlCommand cmd =
    new MySqlCommand("delete from sample where id = @id", cn);
// パラメータ設定
cmd.Parameters.Add(
    new MySqlParameter("id", id));
// オープン
cmd.Connection.Open();
// 実行
cmd.ExecuteNonQuery();
// クローズ
cmd.Connection.Close();

ここまで来ると簡単ですね。

 

■データを更新 UPDATE

更新も同じように書きます。

int id = 20; // 更新するID

MySqlConnection cn = new MySqlConnection(
        "Data Source=localhost;Database=konicadb;User ID=konica;password=konica");
// コマンドを作成
MySqlCommand cmd =
    new MySqlCommand("update sample set updatedate = @date where id = @id", cn);
// パラメータ設定
cmd.Parameters.Add(
    new MySqlParameter("id", id));
cmd.Parameters.Add(
    new MySqlParameter("date", DateTime.Now));
// オープン
cmd.Connection.Open();
// 実行
cmd.ExecuteNonQuery();
// クローズ
cmd.Connection.Close();

こんな風にパラメータを使うと、順不同に書けるのコードも見やすくなります。
■DataSetをいつ更新するのか?

 

所詮 DataSet はキャッシュなので、データの追加/削除/更新した場合は、もう一度 DataSet を読み直すのが吉です。

DataSet/DataTableの内容を直接更新することも可能ですが、かえってややこしいので、業務的にはやめたほうがいいです。

# LINQ to SQL や ADO.NET Data Entity の場合は、オブジェクト自身そのものを通すので、更新しなくても良いでしょう。ただし、SQL Server と Oracle しか使えないので。

手順としては、

・追加したら検索
・削除したら検索
・更新したら検索

にします。

具体的には、

MySqlConnection cn = new MySqlConnection("...");
// コマンドを作成
MySqlCommand cmd =
 new MySqlCommand("insert into TPerson ( @id, @name, @age )", cn);
cmd.Parameters.Add(new MySqlParameter("id", 1));
cmd.Parameters.Add(new MySqlParameter("name", "konica"));
cmd.Parameters.Add(new MySqlParameter("age", 100));
// 実行
cmd.ExecuteNonQuery();
// DataTabel/DataSetを再読み込み
MySqlConnection cn = new MySqlConnection("...");
MySqlDataAdapter da = new MySqlDataAdapter(
 "SELECT * FROM TPerson", cn);
da.Fill(m_dt);

のように、ローカルに保存しているDataSet/DataTable(m_dt)に、設定します。

 

■DataSet/DataTableをどのような形式で持つのか?

実は、例では Tsample 簡単なテーブルをデータグリッドに表示するだけなのですが、実務ではもっと複雑な形式でグリッドに表示することになります。
この場合は、どのパターンでデータを保存するかを「考える」必要があります。

ひとまず、アンチパターンを書き並べておくと、

・複数テーブルを利用している場合、それぞれのテーブルをDataTableに保管しようとする。
・グリッドに表示するときに、常に複雑なフィルタが必要になる。

ような設計になっている場合は、考え直してください。
このような設計は、非常にデータをシンプルに検索する方法に変更します。

指針としては、

.データグリッドやリストに表示する単位で、DataSet/DataTable に保存する。

でOKです。

例えば、

TPerson
+ id
+ name
+ age
+ companyid

TCompany
+ id
+ name

のようなテーブルがあって、グリッドに

+ TPerson.name
+ TCompany.name

の2つを表示している場合には、

MySqlDataAdapter da = new MySqlDataAdapter(
 "SELECT p.name as 'PName', c.name as 'CName' " +
    " FROM TPerson p, TCompany c " +
    " WHERE p.companyid = c.id ";
DataTable dt = new DataTable();
// 実行
da.Fill(dt);

のように、DataTable に保存しておきます。

 

これを表示する画面ごとに取得してしまいます。
昔ならば、メモリが問題になってしまうのですが、今のコンピュータならば、多少のメモリのロスは大丈夫でしょう。
逆に、大量のデータをグリッドに表示するような場合は、DataSetに保存せずに、一回ずつ検索したほうが良いし、表示形式そのものを考え直す必要があります。

カテゴリー: 開発, MySQL | 6件のコメント

C#でMySQLをDataSetで扱う

射撃しつつ前進する方への援護射撃です。

群馬に行った時、データセットの件で「う~ん」と思い、なんとなく落とし穴に陥りそうな匂いはしていたのですが、時間が取れずにそのままに。

という訳で遅ればせながら、.NET(C#)でMySQLを扱うときのコツなんかを、詳しめに書いておきます。

■接続方法はADO.NET Driver for MySQL (Connector/NET)を使う

まず、.NETから扱えるように下記をダウンロードしてインストールします。

MySQL :: Download Connector/Net

http://www-jp.mysql.com/downloads/connector/net/

20100827_01.jpg

■名前空間は MySql.Data.MySqlClient

SQL Server の場合は System.Data.SqlClient を使いますが、MySQL の場合は MySql.Data.MySqlClient をインポートします。

C# だったら先頭の行に

using MySql.Data.MySqlClient;

でOK

■主なクラス

ADO.NET経由でSQL Serverを扱う場合は、

コネクション SqlConnect

アダプタ SqlDataAdapter

となっています。

これが MySQL の場合は

コネクション MySqlConnect

アダプタ MySqlDataAdapter

となればOK。

巷のADO.NETのサンプルもこれを書き換えれば大抵動きます。

肝心のDataSet、DataTable クラスに関しては、SQL Serverでも MySQL でも同じものを使います。最初のコネクションとアダプタの名前が違うだけです。使い方は統一されているので、クラス名だけ変えれば普通は通ります。

20100827_02.jpg

■サンプル

いわゆる、こんな画面を作ってデータ接続をテストすると場合

20100827_03.jpg

サンプルコードはこちら

// クリアボタン
    private void button1_Click(object sender, EventArgs e)
    {
        // 挿入時のクリア
        dataGridView1.Columns.Clear();
        // バインド時
        dataGridView1.DataSource = null;
    }

    // DataSetボタン
    private void button2_Click(object sender, EventArgs e)
    {
        // コネクション作成
        MySqlConnection cn = new MySqlConnection(
            “Data Source=localhost;Database=konicadb;User ID=konica;password=konica”);
        MySqlDataAdapter da = new MySqlDataAdapter(
            “SELECT * FROM sample”, cn);
        DataTable dt = new DataTable();
        // 検索
        da.Fill(dt);
        // 表示
        dataGridView1.DataSource = dt;
        // データ保持
        m_dt = dt;

    }
    ///
    /// データ保持用
    ///
    DataTable m_dt;

    // DataSet自前ボタン
    private void button3_Click(object sender, EventArgs e)
    {
        // コネクション作成
        MySqlConnection cn = new MySqlConnection(
            “Data Source=localhost;Database=konicadb;User ID=konica;password=konica”);
        MySqlDataAdapter da = new MySqlDataAdapter(
            “SELECT * FROM sample”, cn);
        DataTable dt = new DataTable();
        // 検索
        da.Fill(dt);
        // 自前で表示
        dataGridView1.Columns.Add(“ID”, “ID”);
        dataGridView1.Columns.Add(“name”, “名前”);
        foreach (DataRow item in dt.Rows)
        {
            int n = dataGridView1.Rows.Add();
            dataGridView1.Rows[n].Cells[0].Value = item["id"];
            dataGridView1.Rows[n].Cells[1].Value = item["name"];
        }
    }

    // 保存済みのDataSetボタン
    private void button4_Click(object sender, EventArgs e)
    {
        // 表示
        dataGridView1.DataSource = m_dt;
    }

    // LINQは動かせない
    private void button5_Click(object sender, EventArgs e)
    {
        // これはSQL Serverしかできない
        string cnstr = “Data Source=localhost;Database=konicadb;User ID=konica;password=konica”;
        DataContext dc = new DataContext(cnstr);
        var tb = dc.GetTable();
        dataGridView1.DataSource = tb;
    }

    [TableAttribute(Name = "sample")]
    public class TSample
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public DateTime UpdateDate { get; set; }
    }

データグリッドで表示するだけならば、DataSourceプロパティを使ったほうが簡単です。列名なんかが固定であれば、デザイン時に表示する文字列を入れて、バインドする列名を入れておけばOK。

DataSet(ここではDataTable)の使いどころは、保存済みのDataSetボタンのところのように、一度キープしたものをデータベースに接続せずに使えることですね。いわゆるキャッシュの役割です。

当然、DataSetに一時的に更新状態をキープして、一気にデータベースにコミット、という流れもできるんですが、型付きDataSetを作らないと効率的でないので、最初は避けたほうがよいかなと思っています。MySqlCommand を使って、ちまちま INSERT文やUPDATE文を書いたほうが、後々の見通しが良くなります(経験上ですが)。

■DataSetとは何ぞや?

という訳で、DataSetとは何ぞやを、もうちょっと。

最初にデータベース接続に関しては歴史的に、

– ODBC接続

– RDO,DAO,ADO

– ADO.NET, DataSet

– ADO.NET, 型付きDataSet

– LINQ to SQL

– ADO.NET Data Entity

な流れがあります。

ODBC接続は、SQL文を流してちまちまと受け取る方法ですね。Oracleで埋め込み型のPL/SQLを使っているとカーソルを使ったり、フェッチを使ったりとややこしいことこの上ないのですが、C言語からモロ扱えるしろものです。今でも結構やります。

これじゃあ、大変という訳でRDO,DAO,ADOなんてのが出来ました。

主にVBやExcel VBAから使っていたもので、接続する方法をCOM/ActiveXなんかで扱えるようになっています。VB6ぐらいにはお世話になったものです。VB6自体は本格的なオブジェクト指向言語ではない(一部、クラスが使えますが)ので、C++で作成したActiveXを使うという形で、「オブジェクト」を扱うん出うのです。

これを VC++で使っていたりしました。

この最終形のADO(ActiveX Data Objects)の.NET版が、ADO.NETです。

最初は、ADOの移植版という形。

その中でDataSetというのが、データキャッシュの役割を持ちます。

おそらく当時、ASP.NETを作った関係で、WEBサイトのキャッシュをする必要があってのDataSetかなぁ、と。

最初、DataSetは型がない(列名を持たない)ので、アクセスするときのパフォーマンスが落ちました。また、C#のような厳密にメンバを指定したい場合なんかは、文字列で列名を書くのはちょっと…な感じでした(Row[“name”]みたいなの)。

これを、Tsample.name のようにプロパティ名にしたいなぁ、と思ったのが型付きDataSetの始まりです。

この型付の話は、当時、データベースとオブジェクト指向を繋げるという意味で、「O/Rマッピング」と言われています。今では、この手の自動生成ツール(Ruby on Railsとか)が主流になりましたが、その最初の頃ってな感じです。

O/Rマッピングが流行って、データベースからクラスのコードを自動生成してくるのに慣れてくると、一方で SQL 文をプログラマが書かなくなったんですね。自前のデータアクセス方法を提案し始めたというところです。

それが、LINQであったり、という訳で、LINQ to SQL なんかがあります。

LINQ自体は、データベースに限らないのですが、まあ、関数言語の良いとこ取りな感じで。

一方で、ADO.NET Data Entity というのがあって、これがDataSetの正式な子供ですね。Visual Studio でデータベースに接続して、データクラスを自動生成してってやり方です。

このような流れの中で、MySQL は

– ADO.NET, 型付きDataSet

– LINQ to SQL

– ADO.NET Data Entity

のところが使えません。厳密には型付きDataSetは使えるのですが、ちまちまと自前で作らないといけないので、メンテ上非常に大変(それを上回る保守コストならば別ですが)。

なので、MySQL+.NETという組み合わせでは、MySQLのConnectorを使って DataSet/DataTable を使うのが定番かと思います。

■DataSetの使いどころ

MSさんの宣伝記事ならば、

DataSetで、複数のデータ更新ができるのでデータベースに直結せずに、全てのCRUD処理をDataSetを媒介したほうが効率が良い。

20100827_04.jpg

と言いたいところなのですが、現場レベルとしては、ちょっと困るところが出てきます。

1)複数のテーブルが連携しているときの処理が分かりずらい。

2)大量のデータを更新中に、DataSet内で止まってしまう。

のようなお困りが発生します。

1)のほうは、マスターテーブルのような単純なテーブルに関しては DataSet/DataTable を使うと非常に早く更新ができるので楽です。

ですが、他のテーブルのリレーションがあった場合、同時更新などで別のキーを参照する場合の時は、コミットする前の場合、DataSet内のテーブルを探らないと駄目なので、この処理が非常に面倒です。なので、この場合は、トランザクションを付けて、直接データベースにアクセスしたほうが楽にコーディングができます。

2)のほうは、致命的なところがあって、データ量が非常に多くなる(1万件など)場合は、DataSet自体のメモリが大きくなると同時に、更新時にいちいちデータのチェックが走るので、結構重たい処理になってしまいます。この更新処理をDataSet内部のコードを弄って、分割したりするよりは、素直に更新時は直接データベースにアクセスにしに行ったほうがすっきりしたコードが書けます。

という訳で、実際はこんな風に使います。

20100827_05.jpg

ええ、なんか見たことがある矢印の向きですよね。

20100827_06.jpg

こんな風に、MVCスタイルにするとコードが見やすくなります。

つまり、コントローラ部分を分離させた方が、コードの見通しが良くなる、という予想が立ちます(実際、そうなります)。

カテゴリー: 開発, MySQL | 6件のコメント

.NET(C#)でXML-RPCを使ってブログに投稿する

Moonmile Solutions Blog » .NET(C#)でRSSフィードを受信する
http://www.moonmile.net/blog/archives/1234

の続きで、今度は wordpress に投稿するAPI な話。

モノ的には、XML-RPC.Net
http://www.xml-rpc.net/

を使って、wordpress にコマンドラインから投稿ができるところまで作ります。

■xml-rpc.net をダウンロード&ビルド

最初に、http://www.xml-rpc.net/ から、ライブラリをダウロードします。現時点では、Version 2.4.0 ですね。

このzipファイルを解凍して、プロジェクトを見ると、xmlrpc なるプロジェクトがあるので、ビルドします。

ここで注意が必要なのは、そのままビルドしようとすると、

エラー 1 アセンブリ ‘D:\work\kidtwi\src\ReadRSS\xmlrpc\obj\Debug\CookComputing.XmlRpcV2.dll’ を署名しているときに暗号に失敗しました — ‘キー ファイル ‘..\CookComputing.key’ の読み込み中にエラーが発生しました — 指定されたファイルが見つかりません。 ‘ xmlrpc

のようなエラーが発生します。これは署名ファイルを探しているときにファイルがないというエラーなので、本来ならば署名ファイルを用意するべきなのですが、面倒なので、

AssemblyInfo.cs ファイルの該当箇所をコメントアウトします。

[assembly: AssemblyDelaySign(false)]
//[assembly: AssemblyKeyFile(“..\\CookComputing.key”)]
[assembly: AssemblyKeyName(“”)]

これでビルドをすればOK。

対象のフレームワークは、ツールに合わせて「.NET Framework 4」などに変更すればよいでしょう。

■xmlrpcプロジェクトを参照設定する

ツール用のプロジェクトを作って、先のxmlrpcプロジェクトを参照設定します。

あるいは、できあがった CookComputing.XmlRpcV2.dll を参照設定します。

■xmlrpcプロジェクトを参照設定する

投稿時のコードの全文はこれです。

using CookComputing.XmlRpc;
namespace AutoPost
{
    class Program
    {
        static void Main(string[] args)
        {
            Program pg = new Program();
            // コンソールから取得
            string title = Console.In.ReadLine();
            string content = Console.In.ReadToEnd();
            // 投稿
            pg.BllogerNewPost(title, content);
        }

        // ユーザー名
        string username = “<ブログのユーザー名>”;
        // パスワード
        string password = “<ブログのパスワード>”;
        // 投稿先のURL
        string url = “<投稿先のURL>”;

        public void BllogerNewPost(string title, string content)
        {
            //プロキシクラスのインスタンスを作成
            IBlogger proxy = (IBlogger)
                CookComputing.XmlRpc.XmlRpcProxyGen.Create(
                typeof(IBlogger));
            //URLを指定
            proxy.Url = url;

            int id = 0;
            // content を生成
            content = string.Format(“<title>{0}</title>”, title)
                + string.Format(“<category>{0}</category>”, 3)
                + content;
            try
            {
                //blogger.getRecentPostsを呼び出す
                id = proxy.newPost(
                    “”,             // WordPressの場合は無視
                    “1”,            // 念のため1にしておく
                    username,
                    password,
                    content,
                    false);
            }
            catch (Exception ex)
            {
                Console.WriteLine(“エラー:” + ex.Message);
                return;
            }

            //結果を表示する
            Console.WriteLine(“id: ” + id);
        }

    public interface IBlogger : IXmlRpcProxy
    {
        /// <summary>
        /// 新規投稿
        /// </summary>
        /// <param name=”appkey”>無視</param>
        /// <param name=”blogid”>無視</param>
        /// <param name=”username”>ユーザー名</param>
        /// <param name=”password”>パスワード</param>
        /// <param name=”content”>本文</param>
        /// <param name=”publish”>公開するかどうか</param>
        /// <returns>エントリのIDを返す</returns>
        [XmlRpcMethod(“blogger.newPost”)]
        int newPost(
            string appkey,
            string blogid,
            string username,
            string password,
            string content,
            bool publish );
    }
}

キーポイントは、

  • プロキシクラスを作る(IBloggerのところ)
  • メソッドは、XmlRpcMethod で属性として指定する。
  • 実行時に、XmlRpcProxyGen クラスでプロキシを生成する。

XML-RPC で呼び出す時のメソッドは、XmlRpcMethod 属性で指定しますが、blogger api では、タイトルと本文を

<title>タイトル<title>本文…

な感じで書きます。

カテゴリも指定する場合は、

<title>タイトル<title><category>1</category>本文…

このように、カテゴリIDを指定します。

※ このカテゴリIDを取得するのが一苦労なんですよね……データベースを直接見るか、wordpressのapiを使ってリストを呼び出して調べるか、という方法になります。カテゴリの一覧を取得する方法は後日。

このソースでは、標準入力から投稿用のデータを入れています。

最初の一行目はタイトル
<p>二行目から本文を書きます。</p>
<p>そのまま投稿されるのでHTML形式で書いておきます。</p>
<ul>
<li>こんな風に
<li>箇条書きとかも書けますね。
</ul>

こういう形で、1行目はタイトル、続く2行目からは本文になります。本文は、そのまま表示されるのでHTML形式で書いておきます。

■投稿を実行する

実際に投稿をしてみると、

D:\work\kidtwi\src\ReadRSS\AutoPost\bin\Debug>AutoPost.exe  < post1.txt
id: 1279

こんな風に、投稿に成功したときには、IDを返してくれます。

■参照先

結構参考にしたので、並べておきます。

XML-RPCとは何ぞや?の話とかは、こちらをどうぞ。

[WordPress] XML-RPC を使用する方法 | Sun Limited Mt.
http://www.syuhari.jp/blog/archives/1373
MovableType で使える XML-RPC API
http://www.na.rim.or.jp/~tsupo/program/blogTool/mt_xmlRpc.html
XML-RPC wp ≪ WordPress Codex
http://codex.wordpress.org/XML-RPC_wp
どぼんさんのメールマガジン
http://dobon.net/vb/melma/dotnet74.txt

ここでは、wordpress を対象にしましたが、Blogger の場合は、Google からも API が提供されています。

Developer’s Guide: .NET – Blogger APIs – Google Code
http://code.google.com/intl/ja/apis/blogger/docs/2.0/developers_guide_dotnet.html

 

カテゴリー: 開発 | .NET(C#)でXML-RPCを使ってブログに投稿する はコメントを受け付けていません