C#
WPF
access
MDB

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

More than 1 year has passed since last update.

社内の既存システムによって作られている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