LoginSignup
10
13

More than 3 years have passed since last update.

C#,WPF mdbに接続してデータを読み込む

Last updated at Posted at 2017-06-15

社内の既存システムによって作られているmdbファイルに接続してデータの読込がしたかった

mdbとの接続

接続にはOleDbConnection、OleDbCommand 、OleDbDataReader とかを使うらしい

1.OleDbConnectionの準備

string provider = "Microsoft.Jet.OLEDB.4.0;";
string dataSource = "mdbファイルのパス";
OleDbConnection connection = new OleDbConnection("Provider = " + provider + ";Data Source = " + dataSource + ";");

OleDbConnectionコンストラクタの引数はConnectionStringで、接続先の情報とかを指定する

providerはデータベースを制御するデータベース・エンジンの種類のことらしい
mdbファイル ⇨ "Provider=Microsoft.Jet.OLEDB.4.0"
accdbファイル ⇨ "Microsoft.Ace.OLEDB.12.0"
でOK

dataSourceは接続するmdbファイルのパスを指定すればOK

2.OleDbCommandの準備

string queryString = "SQL文";
OleDbCommand command = new OleDbCommand(queryString,connection);

OleDbCommandコンストラクタは第一引数にstringで記述したSQL文、第二引数にOleDbConnectionを指定する

3.接続して読み込む

connection.Open();
var dataReader = command.ExecuteReader();

OleDbConnectionのOpen()で接続する
OleDbCommandのExecuteReader()でデータをOleDbDataReader型に読み込む

4.データを整形する

そのままDataTableへ

var table = new DataTable();
table.Load(dataReader);

データをそのままDataTableにするならDataTableのLoad()でOleDbDataReaderを指定するだけでOK
WPFのDataGridとかに表示させるだけなら多分これが一番簡単

一つづつ取り出す

while (dataReader.Read())
{
    dataReader.GetValue(ordinal)
}

OleDbDataReaderのRead()でレコードを読み込む
こいつは次のレコードがなくなればfalseを返すのでwhileの条件に入れている
OleDbDataReaderのGetValue()でデータが取得できる
引数には列番号をintで指定する
列とか関係なく全部取得するなら

while (dataReader.Read())
{
    for(int i =0; i< reader.FieldCount; i++)
    {
        Console.WriteLine(reader.GetValue(i));
    }
}

でOK
ただ、これだと整形しづらい

例えばこんなDBがあるとして

ID 名前 年齢 性別
1 鈴木 健太 23
2 中村 明 26
3 山下 久美 21

こんなクラスのコレクションにデータを入れたい時

public class Person
{
    public string Name { get; set; } = "";
    public int Age { get; set; }
    public string Gender { get; set; } = "";
}

mdbへの接続から一連の流れも含めて書いてみる
(WPFでReactivePropertyを使って実装)

Model

public class Model
{
    public ReactiveCollection<Person> PersonList { get; set; } = new ReactiveCollection<Person>();

    public void ConnectTomdb(string path)
    {
        string provider = "Microsoft.Jet.OLEDB.4.0;";
        string queryString = "SELECT 名前,年齢,性別 FROM テーブル1";
        OleDbConnection connection = new OleDbConnection("Provider = " + provider + ";Data Source = " + path + ";");
        OleDbCommand command = new OleDbCommand(queryString, connection);
        try
        {
            connection.Open();
            var dataReader = command.ExecuteReader();
            PersonList.Clear();
            foreach (var person in DataReaderConvertToClass(dataReader))
            {
                PersonList.Add(person);
            }
        }
        catch (Exception e)
        {
            MessageBox.Show(e.Message);
        }
        finally
        {
            connection.Close();
        }
    }

    private IEnumerable<Person> DataReaderConvertToClass(OleDbDataReader dataReader)
    {
        while (dataReader.Read())
        {
            var person = new Person();
            var properties = person.GetType().GetProperties();
            for (int i = 0; i < properties.Count(); i++)
            {
                var data = dataReader.GetValue(i);
                if (!data.GetType().Equals(DBNull.Value.GetType())) properties[i].SetValue(person, data);
                //これでもOK
                //if (!string.IsNullOrWhiteSpace(data.ToString())) properties[i].SetValue(person, data);
            }
            yield return person;
        }
    }
}

public class Person
{
    public string Name { get; set; } = "";
    public int Age { get; set; }
    public string Gender { get; set; } = "";
}

OleDbDataReaderはDataReaderConvertToClassメソッドに渡して読み込み、
そこでPersonクラスを作って読み込んだ値をプロパティに詰めてPersonクラスをIEnumerableで返している
返ってきた値はPersonListにAddしている

Personクラスの各プロパティは、インスタンスにGetType()してGetProperties()すると取得できる
OleDbDataReaderのGetValue()でもindexを指定するのでfor文を使って各プロパティにSetValue()している

※GetProperties()すると上から順にプロパティを取得するので、DBの取得する列に合わせてプロパティを設定する必要が有るので注意

ちなみに、DBの値が空白だとGetValue()した時にSystem.DBNullが返ってきて、それをSetValueすると例外がでるので回避しとくこと

ViewModel

public class ViewModel
    {
        public Model _Model { get; set; } = new AccessDBModel();
        public ReactiveProperty<string> _Path { get; set; } = new ReactiveProperty<string>();
        public ReactiveCommand C_getDB { get; } = new ReactiveCommand();

        public ViewModel()
        {
            C_getDB = _Path
                .Select(x => !string.IsNullOrWhiteSpace(x))
                .ToReactiveCommand();
            C_getDB.Subscribe(_ => _Model.ConnectTomdb(_Path.Value));
        }
    }

とても単純
_PathはmdbファイルのパスでTextBoxとかにバインド
C_getDB はデータを取得するコマンドで、_Pathが空白出ない時のみ有効にしている
コマンドではModelのConnectTomdbを呼び出し、_Pathの値を渡している

View

<DataGrid x:Name="dataGrid" ItemsSource="{Binding _Model.PersonList}" HeadersVisibility="Column" >
    <DataGrid.CellStyle>
        <Style TargetType="DataGridCell">
            <Setter Property="TextBlock.TextAlignment" Value="Center"/>
        </Style>
    </DataGrid.CellStyle>
</DataGrid>
<TextBox Text="{Binding _Path.Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<Button Content="Load" Command="{Binding testCommand, Mode=OneWay}"/>

自動生成に任せるならこんな感じ
Collectionにしてバインドすると自分で列を指定していろいろカスタムすることもできる
また、DataTriggerを設定したら特定の値のある行に色をつけたりとかもできる

パスをいれてボタンを押すとこんな感じで取得できる
2017-06-15_09h31_41.jpg

おわりに

読み込むだけならかなり簡単
とりあえず書き込みをすることはないので必要になれば調べるかも
同時接続とかは検証してない(・・;

参考:MSDN/OleDbConnection

10
13
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
13