あとらすの備忘録

チラ裏のメモ帳

ASP.NET MVCでCRUD ツイートレスポンスを登録する

ツイートレスポンスの内容をDBに登録してみる。

前回の続きです。
kitigai.hatenablog.com

ツイートするとレスポンスを受け取ることができるので
そのレスポンス内容をDBに登録してみます。
いわゆるCRUDです。(Create Read Update Delete)

実行環境

ソース

github.com

ASP.NET MVCCRUD

こちらの記事が大変参考になりました。
qiita.com

DB接続文字列の設定

DBに接続するための設定部分をいじります。

プロジェクト直下/Web.config
//改変前
<connectionStrings>
   <add name="DefaultConnection" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\aspnet-TweetTest-20180102122324.mdf;Initial Catalog=aspnet-TweetTest-20180102122324;Integrated Security=True" providerName="System.Data.SqlClient" />
</connectionStrings>
//改変後
<connectionStrings>
   <add name="MyContext" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\aspnet-TweetTest-20180102122324.mdf;Initial Catalog=aspnet-TweetTest-20180102122324;Integrated Security=True" providerName="System.Data.SqlClient" />
</connectionStrings>

name部分のDefaultConnectionをMyContextに変更します。
ほかはいじっていません

自前で用意したDBは使用せず既存のDBを使用するので
この設定変更はいらないと思いしていなかったのですが
していない状態でうまくいかなかったので
参考にしたQiitaの記事通りに設定します。

Modelの準備

ツイートレスポンスを格納するためのモデルを用意します。

    public class TweetResult
    {
        public int id { get; set; }
        public string tweet { get; set; }
        public string tweetId { get; set; }
    }
    public class MyContext : DbContext
    {
        public DbSet<TweetResult> TweetResults { get; set; }
    }

MyContextにて、物理テーブル(Members)にマップしています。*1

マップ?とは何ぞやって感じですが
TweetResultsテーブルと対をなすのはこのTweetResultモデルですって
明示するって感じであってますか?(ちゃんと調べる。)

テーブルの準備

順序が逆な気が超しますが、テーブルを作成します。

CREATE TABLE [dbo].[TweetResults] (
    [id]      INT            IDENTITY (1, 1) NOT NULL,
    [tweet]   NVARCHAR (MAX) NULL,
    [tweetId] NVARCHAR (MAX) NULL,
    CONSTRAINT [PK_dbo.TweetResults] PRIMARY KEY CLUSTERED ([id] ASC)
);

とりあえず動けばいいやーで作ってたらこんなのになってしまった。
TweetのIDってLong型で返ってくるんですね・・・

Controllerに登録部分を作成

とりあえずController部分のソース
余計なコメントは気にしない

    public class TweetController : Controller{
        //DBコネクションのインスタンス?であってる?
        private MyContext db = new MyContext();

        //...中略

        //テーブルを参照する際、awaitを使用しているのでasyncに変更?
        public async Task<ActionResult> TweetPost(TweetViewModels tt){
            //...中略

            //ツイート後、レスポンス取得 CoreTweet.StatusResponse
            var res = tokens.Statuses.Update(status => DateTime.Now + " " + tt.TweetText);

            var tr = new TweetResult{
                id = 1,
                tweet = res.Text,  //ツイート内容
                tweetId = res.Id.ToString()  //ツイートID
            };

            db.TweetResults.Add(tr);   //テーブルに追加
            db.SaveChanges();    //データの変更をコミット

            return View(res);
        }
        public ActionResult Result(){
            var tr = db.TweetResults.ToList();
            return View(tr);
        }
    }

参考記事にはControllerでいくつもContextを生成しないために
全体で使用できるよう定義しているのでそのまま真似します。

HomeController全体で利用するContextをdbとして定義。*2

ツイートのレスポンスからツイート内容とツイートIDを
TweetResultクラスに突っ込みます。
(※IDはほんとは自動インクリメントのインデックス番号にしたかった)

その作成したTweetResult(tr)をAddにてテーブルに追加します。

コミット

これでいいのかーと思いきや
SaveChangesを実行しないとDBコミットされないようです。

これで準備おっけ!

ツイートして登録されるか確認する

f:id:HM_Atlas:20180108200900p:plain

完璧。
エラーと格闘中に一覧表示のViewも作ったのでそっちでも確認してみる。
f:id:HM_Atlas:20180108201042p:plain

トラブルシュート

本当はここが書きたかった
まずはこれを見てくれ
f:id:HM_Atlas:20180108202345p:plain

こんなエラーが出ました。

There is already an object named '__MigrationHistory' in the database.

こいつに俺の3連休はつぶされた!!!!(大袈裟)

"__MigrationHistory"って名前のテーブル(オブジェクト?)はもうDBに存在するよーって言ってますよね?
作った覚えないんですがそれは・・・

とりあえずググる
stackoverflow.com
うわあああああああ、苦手な英語のページしかヒットしなーい

接続文字列が変更されたから__MigrationHistoryって言うテーブルを再作成しなさい?
見たいな感じですかね?結局よくわからなかったんですよね

サーバーエクスプローラーを確認してみる
f:id:HM_Atlas:20180108203048p:plain

こいつか存在するからエラーが起きるなら消してみよう
削除後、実行するとうまくいきました。
そして再度確認すると__MigrationHistoryが再作成されていました。

想像

たぶんテーブルを手動作成の下りがいらなかった?
参考文献の中にコードファーストとかDBファーストなんて言葉が出てきたけど
モデルの中にDbContextを定義したら自動でテーブルが作成されたりします?
これ、要検証でまだ検証とか調べたりとかはしてません。

雑感

また寄り道プログラミングをしてたら正規表現が思ったより難しく
時間を食ったりして、それもまた中途半端になったり

簡単にできると思って始めたASP.NETはわけがわからなくなってきているし
何をググればいいかわからない状態なのが一番つらい

この三連休、月末に上京するときに面談とか行きたいところ
探そうと思ってたらコード書いて終わった・・・