DB を設計していると、ひとつの列で bool 値をまとめてしまおうという発想をすることがある。ほとんどのケースで、これは設計ミス(アンチパターン)となりやすいことで知られ、jaywalking(信号無視)パターンと言います。
どうして jaywalking パターンは、悪いのか。
カラムに文字数制限があれば(わかりづらい)上限になること、格納されるカラム名が無いから仕様書がないと情報が減ること(=誤ったデータを挿入して運用を進めると困ったことになる)……色々考えられると思います。
なので、本当だったらあんまり使いたくない。でも、既存 DB で使われている場合や、参照の少ない履歴を管理するテーブルで(僅かな)容量削減を目的に利用されてたりする。さて、どうしよう。
リファクタリングするにしても、リファクタリングをする価値のないデータやプロジェクトであるなら、そこに時間を投資しても困る。したくない。残念ながら、(体力だったり、政治だったりを含め)色々な理由でやむを得ないケースはある。
そんなわけで、DB 上に存在することを想定した byte (int) 型のデータを複数の bool 値に変換したり、その逆をしたりするサンプルです。
byte to bool[8]
private bool[] ToBools(byte data) { var bools = new bool[8]; for (int i = 0; i < 8; i++) { bools[i] = (data & (1 << i)) != 0; } Array.Reverse(bools); return bools; }
bool[8] to byte
private byte ToByte(bool[] sources) { byte result = 0x00; int index = 8 - sources.Length; if (sources.Length <= 0) { return result; } foreach (var source in sources) { if (source) { result |= (byte)(1 << (7 - index)); } index++; } return result; }
サンプル
WPF の binding を利用するとこんな感じになると思います。IsEnabled1 ~ IsEnabled8 は、8つのチェックボックス IsChecked プロパティにそれぞれ対応。
public byte Result { get { var bools = new bool[8]; bools[0] = IsEnabled1; bools[1] = IsEnabled2; bools[2] = IsEnabled3; bools[3] = IsEnabled4; bools[4] = IsEnabled5; bools[5] = IsEnabled6; bools[6] = IsEnabled7; bools[7] = IsEnabled8; return ToByte(bools); } set { var bools = ToBools(value); IsEnabled1 = bools[0]; IsEnabled2 = bools[1]; IsEnabled3 = bools[2]; IsEnabled4 = bools[3]; IsEnabled5 = bools[4]; IsEnabled6 = bools[5]; IsEnabled7 = bools[6]; IsEnabled8 = bools[7]; } }
これも当然ながら、jaywalking パターンらしい欠点を持つ byte 型を格納することになる。