Quantcast
Channel: rana_kualuの記事 - Qiita
Viewing all articles
Browse latest Browse all 331

C#でMySQLからSELECTした結果を取り出したい

$
0
0

C#は素人なのと、あとコードは再現なので不適切なコードになっている可能性が高いです。
おそらくもっといい解法があるはずですが、調べた限りではよくわかりませんでした。

課題

テーブルAからSELECTする、テーブルBからSELECTする、その後ふたつのデータを色々やって最後にテーブルCにインサートする、みたいなことがやりたかったわけですよ。
コード側で色々と処理を行う必要があるため、一度コード側にデータを引き取るのが前提です。

問題

ベストプラクティスがわからない。
適切なサンプルコードが見付からない。

信頼できるドキュメントはMicrosoft公式くらいしかないわけですが、そこに載ってるサンプルコードはどうにも役に立ちません。

https://docs.microsoft.com/ja-jp/azure/mysql/connect-csharp
https://docs.microsoft.com/ja-jp/dotnet/api/overview/azure/mysql?view=azure-dotnet

公式サンプルの例
using(MySqlConnectionconn=newMySqlConnection(connectionString)){conn.Open();// SQL発行MySqlCommandselectCommand=newMySqlCommand("SELECT * FROM MyTable",conn);MySqlDataReaderresults=selectCommand.ExecuteReader();// 行ごとにループwhile(results.Read()){Console.WriteLine("Column 0: {0} Column 1: {1}",results[0],results[1]);}}

ループ中でログ出力する例しか載ってない。
そんな役に立たないコードじゃなくてもっとこう、取得結果をreturnして他所で使い回す方法はないんですかね。

しかもresults[0]とか、今どき列番号で取ってくるなんて有り得ないじゃろ。
列名で取ってきてくれよ。

やってみた

// メインpublicstaticvoidMain{MySqlConnectionmySqlConnection=newMySqlConnection("ConnectionString");mySqlConnection.Open();vartableA=getTable("tableA");vartableB=getTable("tableB");}// 取得publicasyncTask<DataReader>getTable(stringtableName){using(varcommand=mySqlConnection.CreateCommand()){command.CommandText=$"SELECT * FROM {tableName}";using(varreader=command.ExecuteReaderAsync()){returnreader;}}}

できた。

はい、これThere is already an open DataReader associated with this Connection which must be closed firstとか言われて死にます。
どうもDataReaderは同時にひとつしか開けないらしい。
二つ目のSQLを投げる前に、一つ目のSQLはCloseしなくてはなりません。
Closeすると当然データが取れなくなるので、Closeする前に値を取り出しておかねばならないということです。

少し変更した

DataReaderから値を取得して、Dictionaryに突っ込んで返すようにしました。

staticMySqlConnectionmySqlConnection;publicstaticvoidMain{mySqlConnection=newMySqlConnection("ConnectionString");mySqlConnection.Open();vartableA=getTable("tableA");vartableB=getTable("tableB");}// 取得publicDictionary<string,Dictionary<string,string>>getTable(stringtableName){using(varcommand=mySqlConnection.CreateCommand()){command.CommandText=$"SELECT * FROM {tableName}";using(varreader=command.ExecuteReader()){if(reader.HasRows){while(reader.Read()){JObjectline=newJObject();for(inti=0;i<reader.FieldCount;i++){line.Add(reader.GetName(i),reader.GetString(i));}ret.Add(reader.GetString("id"),line);}}}}returnret;}

これでできた!
と思いきや、何故かこれでもalready an open DataReaderが発生することがあります。
なんで?returnする前にusingの外に出てるやろ?
原因がさっぱりわからなかったので諦めました。

しかも、どうやらその行の列を全て取得するみたいなメソッドがどうも存在しないっぽい。
いちいちFieldCountで列数を調べて全列をループで回して取り出しています。
SQL発行する度に毎回行×列のループを回さねばならないとか、本当かこれ???

そもそも最初からfetchAllがあれば解決なのですよ。
どうしてこの程度のメソッドが用意されてないのですかね?

とりあえず完成

mySqlConnectionを毎回開けばええんや。

publicstaticvoidMain{vartableA=getTable("tableA");vartableB=getTable("tableB");}// 取得publicDictionary<string,Dictionary<string,string>>getTable(stringtableName){using(MySqlConnectionmySqlConnection=newMySqlConnection("ConnectionString")){mySqlConnection.Open();using(varcommand=mySqlConnection.CreateCommand()){command.CommandText=$"SELECT * FROM {tableName}";using(varreader=command.ExecuteReader()){if(reader.HasRows){while(reader.Read()){varline=newDictionary<string,string>();for(inti=0;i<reader.FieldCount;i++){line.Add(reader.GetName(i),reader.GetString(i));}ret.Add(reader.GetString("id"),line);}}}}}returnret;}

いや……一応これで動いたんだけどさあ、どう考えてもおかしいだろ、これ。
SQLを発行するたび毎回MySqlConnectionをnewしてるってことは、PHPで言うと毎回new PDOってしてるってことですよね。
そんな書き方ありえなーい。
そもそも高々SQL発行するだけなのに何重に括らせる気なんだよ。

なんかもっとこう、ちゃんとした正しい書き方ってのがあるよね?
あると思うのですよ。
間違いなく存在するでしょう。

実はありまぁす

DataTableってのがあった。

publicstaticvoidMain{vartableA=getTable("tableA");vartableB=getTable("tableB");}publicDataTablegetTable(stringtableName){DataTabletbl=newDataTable();using(MySqlConnectionmySqlConnection=newMySqlConnection(builder.ConnectionString)){mySqlConnection.Open();using(varcommand=mySqlConnection.CreateCommand()){command.CommandText=$"SELECT * FROM {tableName}";using(varreader=command.ExecuteReader()){tbl.Load(reader);}}}returntbl;}

これでDataTableに全データが入ってくるようで、MySqlConnectionを閉じた後でも問題なく参照することができました。

どう考えても真っ先にこれを紹介すべきなのに、普通に調べたら全然出てこないとかいう。
ここまで調べるのにめっちゃ時間かかった。

なおMySqlConnectionを閉じないとエラーになるのは相変わらずです。
どうやったら使い回せるんですかね?
それ以前に、そもそも本当にコレが最終解なんですかね?

その他

C#では特に目立つ気がするのですが、Stackoverflowを機械訳したようなゴミURLばっかり引っかかってくるのはどうにかならないんですかね?


Viewing all articles
Browse latest Browse all 331

Trending Articles