リード開発メモ

大阪のソフトウェア会社です。 技術的な事柄についてのメモとしてブログを始めます。

2013年10月

Thunderbird で分割メールを結合する

Thunderbird で分割されたメールを受信すると、自動的に結合されない

メッセージ一覧では次のように見える。すなわち送信者と件名などは分かるが、一見しただけでは本文は分からない。
combine-split-mails

このような場合は、分割された先頭のメッセージを選択し、メニュー[表示] - [メッセージのソース] でソースを表示する。するとテキスト形式のメールであれば、ヘッダの直後に本文を見つけることができる。

手動で結合するには、分割されたすべてのメールの添付ファイルを保存する。仮に 1.tml ~ 4.tmp という名前で保存するとする。

次にコマンドプロンプトを立ち上げ、以下のような copy コマンドでファイルを結合する。
C:\tmp>copy 1.tmp + 2.tmp + 3.tmp + 4.tmp combine.eml
1.tmp
2.tmp
3.tmp
4.tmp
        1 個のファイルをコピーしました。

C:\tmp>

結合した combine.eml は Thunderbird で見ることができるし、Thunderbird の任意のフォルダにドロップして追加することもできる。

以上。

C# 継承先フォームから基本フォームに配置したToolStripにアクセスできない

業務アプリではデザインを統一するなど理由で基本フォームを作る場合が多い。各画面は基本フォームを派生して作ることになる。基本フォームに配置したコントロールは、派生先でも変更できるように Modifiers プロパティを protected にしておく。

ただ、基本フォームに ToolStrip を置いていると、派生先フォームのデザイン時に、ToolStrip のプロパティにアクセスできない。プロパティウィンドウがグレイアウトしてしまう。

この現象は FlowLayoutPanel、TableLayoutPanel、ToolStrip、MenuStrip、ContextMenuStrip、StatusStrip、DataGridView、BindingNavigator などでも起こるようだ。

回避方法は、対象となるコントロールの派生クラスを作り、Designer 属性を指定する。Designer 属性に指定する DesignerType は、System.Design.dll を参照設定に追加する必要がある。

ToolStrip の場合は以下のようになる。
[System.ComponentModel.Designer(typeof(System.Windows.Forms.Design.ControlDesigner))]
public partial class InheritedToolStrip : ToolStrip
{
	public InheritedToolStrip()
	{
		InitializeComponent();
	}
}

また、パネルのようなコンテナの場合は ParentControlDesigner を使う。
[System.ComponentModel.Designer(typeof(System.Windows.Forms.Design.ParentControlDesigner))]
public partial class InheritedFlowLayoutPanel : FlowLayoutPanel
{
	public InheritedFlowLayoutPanel()
	{
		InitializeComponent();
	}
}

これらの InheritedToolStrip なり、InheritedFlowLayoutPanel を基本フォームに配置すればいい。Modifiers プロパティを protected にしておく必要はある。

以上。

C# 二重起動防止

C# で二重起動を防止する方法。

名前付きミューテックスを生成し、WaitOne で取得できるかチェックするというもの。待ち時間なしでよい。アプリケーションのエントリポイントで行う。

static class Program
{
    [STAThread]
    static void Main()
    {
        // 二重起動防止
        using (Mutex mtx = new Mutex(false, Application.ProductName))
        {
            if (mtx.WaitOne(0, false))
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());

                mtx.ReleaseMutex();
            }
            else
            {
                MessageBox.Show("すでに起動されています。");
            }
            mtx.Close();
        }
    }
}

PetaPoco を使ってみる(その5)

前回、PetaPoco の Insert/Update/Delete メソッドを使ってみたが、いちいちテーブル名とプライマリーキーを指定していた。

PetaPoco の Insert/Update/Delete メソッドではこれらを省略することができる。そのためには POCO のクラス定義に、テーブル名の属性 TableName とプライマリーキー PrimaryKey を属性として指定しておく。なお、今回の例のようにテーブル名がクラス名と一致している場合は、TableName 属性を指定する必要はなさそうだ。

Product テーブルのキーである ProductId は自動インクリメントID なので、PrimaryKey 属性に「autoincrement = true」を指定している。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
using PetaPoco;
 
namespace PetaPocoTest1
{
    public partial class Form1 : Form
    {
        private string connectionString = "Data Source=(local);Database=ORMTest;User ID=ORMTest_user;Password=ORMTest_password";
 
        public Form1()
        {
            InitializeComponent();
 
            dataGridView1.AutoGenerateColumns = false;
            dataGridView1.Columns.AddRange(
                new DataGridViewTextBoxColumn()
                {
                    DataPropertyName = "ProductId",
                    Name = "ProductId",
                },
                new DataGridViewTextBoxColumn()
                {
                    DataPropertyName = "Name",
                    Name = "Name",
                },
                new DataGridViewTextBoxColumn()
                {
                    DataPropertyName = "Price",
                    Name = "Price",
                },
                new DataGridViewTextBoxColumn()
                {
                    DataPropertyName = "SubCategoryId",
                    Name = "SubCategoryId",
                },
                new DataGridViewTextBoxColumn()
                {
                    DataPropertyName = "SubCategoryName",
                    Name = "SubCategoryName",
                },
                new DataGridViewTextBoxColumn()
                {
                    DataPropertyName = "CategoryName",
                    Name = "CategoryName",
                }
            );
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            var db = new PetaPoco.Database(connectionString, "System.Data.SqlClient");
            var resultList = db.Query<Product, SubCategory, Category, Product>(
                    (p, s, c) => { p.SubCategory = s; s.Category = c; return p; },
                    @"SELECT p.*, s.*, c.* FROM Product p 
                    INNER JOIN SubCategory s ON s.SubCategoryId = p.SubCategoryId
                    INNER JOIN Category c ON c.CategoryId = s.CategoryId"
                );
            dataGridView1.DataSource = resultList.ToList();
        }
 
        private void button2_Click(object sender, EventArgs e)
        {
            var db = new PetaPoco.Database(connectionString, "System.Data.SqlClient");
            var newProduct = new Product() { Name = "弱虫ペダル(30)", Price = 450, SubCategoryId = 100, };
            var newProductId = db.Insert(newProduct);
        }
 
        private void button3_Click(object sender, EventArgs e)
        {
            var db = new PetaPoco.Database(connectionString, "System.Data.SqlClient");
            var resultList = db.Query<Product>(
                    @"SELECT p.* FROM Product p WHERE ProductId >= @ProductId",
                    new { ProductId = 6 }
                );
            resultList.ToList().ForEach(product => {
                product.Name = "ポケットモンスター X";
                product.Price = 3918;
                product.SubCategoryId = 200;
                var newProductId = db.Update(product);
            });
        }
 
        private void button4_Click(object sender, EventArgs e)
        {
            var db = new PetaPoco.Database(connectionString, "System.Data.SqlClient");
            var resultList = db.Query<Product>(
                    @"SELECT p.* FROM Product p WHERE ProductId >= @ProductId",
                    new { ProductId = 6 }
                );
            resultList.ToList().ForEach(product =>
            {
                var newProductId = db.Delete(product);
            });
        }
    }
 
    [TableName("Product")]
    [PrimaryKey("ProductId", autoIncrement = true)]
    public class Product
    {
        public int ProductId { get; set; }
        public string Name { get; set; }
        public int Price { get; set; }
        public int SubCategoryId { get; set; }
 
        [ResultColumn]
        public SubCategory SubCategory { get; set; }
        [ResultColumn]
        public string SubCategoryName { get { return SubCategory.Name; } }
        [ResultColumn]
        public string CategoryName { get { return SubCategory.Category.Name; } }
    }
 
    [TableName("SubCategory")]
    [PrimaryKey("SubCategoryId", autoIncrement = false)]
    public class SubCategory
    {
        public int SubCategoryId { get; set; }
        public string Name { get; set; }
        public int CategoryId { get; set; }
 
        [ResultColumn]
        public Category Category { get; set; }
    }
 
    [TableName("Category")]
    [PrimaryKey("CategoryId", autoIncrement = false)]
    public class Category
    {
        public int CategoryId { get; set; }
        public string Name { get; set; }
    }
}

Insert/Update/Delete メソッドが少しすっきり書けるだけであるが、POCO の定義は一度だけで、何度もInsert/Update/Delete メソッドの呼び出しを行うことを考えれば、ずいぶん助かると思う。

以上

PetaPoco を使ってみる(その4)

今回は PetaPoco を使って INSERT、UPDATE、DELETE をしてみる。

Dapper のときと同じように、フォームにボタンを3つ追加し、button2でINSERT、button3でUPDATE、button4でDELETE の処理を行う。簡単にするため、これらのボタン処理では DB を更新するだけなので、表示に反映させるためには button1 で SELECT しなおす必要がある。

なお、何度か button1 を押すことになるので、グリッドのカラムを設定する処理はコンストラクタに移動させる。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
using PetaPoco;
 
namespace PetaPocoTest1
{
    public partial class Form1 : Form
    {
        private string connectionString = "Data Source=(local);Database=ORMTest;User ID=ORMTest_user;Password=ORMTest_password";
 
        public Form1()
        {
            InitializeComponent();
 
            dataGridView1.AutoGenerateColumns = false;
            dataGridView1.Columns.AddRange(
                new DataGridViewTextBoxColumn()
                {
                    DataPropertyName = "ProductId",
                    Name = "ProductId",
                },
                new DataGridViewTextBoxColumn()
                {
                    DataPropertyName = "Name",
                    Name = "Name",
                },
                new DataGridViewTextBoxColumn()
                {
                    DataPropertyName = "Price",
                    Name = "Price",
                },
                new DataGridViewTextBoxColumn()
                {
                    DataPropertyName = "SubCategoryId",
                    Name = "SubCategoryId",
                },
                new DataGridViewTextBoxColumn()
                {
                    DataPropertyName = "SubCategoryName",
                    Name = "SubCategoryName",
                },
                new DataGridViewTextBoxColumn()
                {
                    DataPropertyName = "CategoryName",
                    Name = "CategoryName",
                }
            );
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            var db = new PetaPoco.Database(connectionString, "System.Data.SqlClient");
            var resultList = db.Query<Product, SubCategory, Category, Product>(
                    (p, s, c) => { p.SubCategory = s; s.Category = c; return p; },
                    @"SELECT p.*, s.*, c.* FROM Product p 
                    INNER JOIN SubCategory s ON s.SubCategoryId = p.SubCategoryId
                    INNER JOIN Category c ON c.CategoryId = s.CategoryId"
                );
            dataGridView1.DataSource = resultList.ToList();
        }
 
        private void button2_Click(object sender, EventArgs e)
        {
            var db = new PetaPoco.Database(connectionString, "System.Data.SqlClient");
            var newProduct = new Product() { Name = "弱虫ペダル(30)", Price = 450, SubCategoryId = 100, };
            var newProductId = db.Insert("Product", "ProductId", true, newProduct);
        }
 
        private void button3_Click(object sender, EventArgs e)
        {
            var db = new PetaPoco.Database(connectionString, "System.Data.SqlClient");
            var resultList = db.Query<Product>(
                    @"SELECT p.* FROM Product p WHERE ProductId >= @ProductId",
                    new { ProductId = 6 }
                );
            resultList.ToList().ForEach(product => {
                product.Name = "ポケットモンスター X";
                product.Price = 3918;
                product.SubCategoryId = 200;
                var newProductId = db.Update("Product", "ProductId", product);
            });
        }
 
        private void button4_Click(object sender, EventArgs e)
        {
            var db = new PetaPoco.Database(connectionString, "System.Data.SqlClient");
            var resultList = db.Query<Product>(
                    @"SELECT p.* FROM Product p WHERE ProductId >= @ProductId",
                    new { ProductId = 6 }
                );
            resultList.ToList().ForEach(product =>
            {
                var newProductId = db.Delete("Product", "ProductId", product);
            });
        }
    }
 
    public class Product
    {
        public int ProductId { get; set; }
        public string Name { get; set; }
        public int Price { get; set; }
        public int SubCategoryId { get; set; }
 
        [ResultColumn]
        public SubCategory SubCategory { get; set; }
        [ResultColumn]
        public string SubCategoryName { get { return SubCategory.Name; } }
        [ResultColumn]
        public string CategoryName { get { return SubCategory.Category.Name; } }
    }
 
    public class SubCategory
    {
        public int SubCategoryId { get; set; }
        public string Name { get; set; }
        public int CategoryId { get; set; }
 
        [ResultColumn]
        public Category Category { get; set; }
    }
 
    public class Category
    {
        public int CategoryId { get; set; }
        public string Name { get; set; }
    }
}

まず、POCO である Product クラスのプロパティのうち、データベースにないプロパティに ResultColumn 属性を付けておく。これをしないと Insert メソッドを呼んだとき、データベースに存在しないカラムということでエラーになってしまう。

INSERT では、 Insert メソッドが用意されているのでこれを使う。自動インクリメントID列もうまく処理してくれる。 Insert メソッドを呼びだした後、引数として渡した Product オブジェクトのProductId には新しく設定された ID が振られている。また、 Insert メソッドの戻り値として新しく設定された ID が取得できる。

UPDATE、DELETE に関しては、SELECT したデータを元に、Update メソッド、Delete メソッドを使うことができるので、生のSQLを書くしかなかった Dapper に比べて非常に使いやすく感じる。もちろん PetaPoco でも必要ならば Execute メソッドを使って生のSQLを実行することもできる。


以上

アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

livedoor 天気
「livedoor 天気」は提供を終了しました。