okinawa

勉強メモ

コードファーストとDBファーストで外部キーの設定

 

コードファースト

・参考

public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
 
public List<Post> Posts { get; set; } //コレクションナビゲーションプロパティ
}
 
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
 
public int BlogId { get; set; } //外部キー
public Blog Blog { get; set; } // 参照ナビゲーションプロパティ
}
 
using Microsoft.EntityFrameworkCore.Migrations;
 
namespace CodeFirst.Migrations
{
public partial class Initial : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Blog",
columns: table => new
{
BlogId = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Url = table.Column<string>(type: "nvarchar(max)", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Blog", x => x.BlogId);
});
 
migrationBuilder.CreateTable(
name: "Post",
columns: table => new
{
PostId = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Title = table.Column<string>(type: "nvarchar(max)", nullable: true),
Content = table.Column<string>(type: "nvarchar(max)", nullable: true),
BlogId = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Post", x => x.PostId);
table.ForeignKey(
name: "FK_Post_Blog_BlogId",
column: x => x.BlogId,
principalTable: "Blog",
principalColumn: "BlogId",
onDelete: ReferentialAction.Cascade);
});
 
migrationBuilder.CreateIndex(
name: "IX_Post_BlogId",
table: "Post",
column: "BlogId");
}
 
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Post");
 
migrationBuilder.DropTable(
name: "Blog");
}
}
}
 

DBファースト

SQLServerで外部キー設定してスキャフォールディングするとこんな感じになる。
・モデルクラス
public partial class Character
{
[Key]
public int CharacterId { get; set; }
public int TeamId { get; set; } // 外部キー
public string CharacterName { get; set; }
public virtual Team Team { get; set; } // virtual型?というのができる。
 
コンテキストクラス
こんな感じで、外部キーが設定される。
entity.HasOne(d => d.Team)
.WithMany(p => p.Characters)
.HasForeignKey(d => d.TeamId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FromFK_character_ToTeam");

 

外部キーを元にLinqでテーブル結合してみる

結合1
SQL感があってわかりやすい。
var query = from photo in context.Set<PersonPhoto>() //photo変数にPersonPhotoテーブルを代入
join person in context.Set<Person>() // person変数にPersonテーブルを代入
on photo.PersonPhotoId equals person.PhotoId // テーブル結合条件
select photo; // PersonPhotoテーブルの列を表示
return View(await query.ToListAsync());
 
結合2
Includeメソッド
なんと簡単ことよ・・・。
var codeFirstContext = _context.Post.Include(p => p.Blog); // IncludeでPostとBlogテーブル結合
return View(await codeFirstContext.ToListAsync());

 

SQL Server Management Studioメモ

SQL Server Management Studio

SQLサーバのGUI。以下SSMS。

ユーザ作成・権限管理

セキュリティの中。ログインがユーザ。

データベースダイアグラム

ダイアグラム便利。

だけど新規作成時に必ずインデックスの境界外エラーが出る。

一度再起動すれば大丈夫。

外部キーの設定

テーブル右クリック→デザイン→列名右クリック→リレーションシップで設定する。

rowversion型が存在しない

SSMSのGUI上ではrowversion型がない。

なのでSQLで打ち込む。

ALTER TABLE tableName ADD 
columnName rowversion NULL;

   ちなみに上記SQLを打っても、GUI上だとTimestamp型と表示されるが実際にはrowversion型らしい。

あとの手順はコードファーストとほぼ一緒。Add-Migration→Update-DatabaseはやらなくてOK。

social.msdn.microsoft.com

自動採番の設定

主キーを設定するだけでは自動採番にならない。

テーブル右クリック→デザイン→列名クリック

→下にある列のプロパティ欄のIDENTITYの指定を「はい」にする。

コードファースト・DBファーストで主キーの名前を変える方法

コードファーストだと主キー名が「Id」か「classNameId」しかつけられない。

Companyクラスなら「Id」か「CompanyId」だけ。  

参考

キー-EF Core | Microsoft Docs

asp.net-core - 「Id」とは異なる名前の主キーを持つ方法 - ITツールウェブ

コードファーストの手順

  ・コンテキストクラスを変更する。

        public DbSet<Test> Test { get; set; }
 
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Test>()
                .HasKey(b => b.Test_id) //←こっちがモデルクラスの名前
                .HasName("Test_id"); // ←こっちがDBのカラム名
        }

VisualStudio内のDBで主キー名変更の場合

主キー名を変える場合は一度DBごと消さないとダメ。

手順は

上記の要領でコンテキストクラス変更→

→DB消す→Add-Migration→Update-Database

DBファースト

・コンテキストクラスを変更する。

modelBuilder.Entity<Account>(entity =>
            {
                entity.ToTable("account");

                // モデルクラスの主キー指定
                entity.HasKey(e => e.AccountId);

                // DBの主キー名はaccount_id
                entity.Property(e => e.AccountId).HasColumnName("account_id");
             }

【.Net Core5】DBファーストでモデルクラス作成からCRUD機能の作成までの流れ

参考サイト

https://mebee.info/2021/02/14/post-28952/  

手順0:DBの作成

テーブル作って、外部キーやら自動採番やらの設定をする。

SSMSでの自動採番の設定はテーブル右クリック→デザイン→列名クリック→列のプロパティでIDENTITYの指定を「はい」にする。

外部キーは列名を右クリックでリレーションシップから。

手順1:SQLサーバとの接続

ここからの操作は全部VisualStudio。

1,ツール→データベースへの接続→MicrosoftSQLServer→続行

2,サーバー名とデータベース名を入力→テスト接続

サーバー名とデータベース名はSSMSでデータベースを右クリック→接続のプロパティで見れる。

3,サーバーエクスプローラを開いて接続したDBを右クリック→プロパティで接続文字列をメモっておく。

手順2:スキャフォールディング

1,Nugetでパッケージインストール

2,プロジェクトを1回ビルドする。

3,dotnetをインストール

PMCでもパワーシェルでもどっちでも良い。

dotnet tool install --global dotnet-ef

4,パワーシェルでscafoldコマンド実行。

プロジェクト名を右クリック→ターミナルで開く、でプロジェクトディレクトリのパワーシェルが開く。

dotnet ef dbcontext scaffold "接続文字列" Microsoft.EntityFrameworkCore.SqlServer -o Models

  接続文字列の調べ方↓

dodosu.hatenablog.jp

5,Modelsフォルダの中身確認

モデルクラスとコンテキストクラスが出来てたら成功。

6,Controllersとビューの作成

Controllersフォルダ右クリック→追加→コントローラ

→EntityFrameworkを使用したビューがあるMVCコントローラ

→先程作成した、モデルクラスとコンテキストを選択する。

→追加。まだ終わりではないのです。

手順3:Startup.csとappsettings.jsonとコンテキストクラスに追記。

1,Startup.csに追記

なぜか依存性の注入がされないので追記。

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();

            // 追記部分。
            services.AddDbContext<TestDBContext>(Options => Options.UseSqlServer(Configuration.GetConnectionString("TestDBContext")));

        }

2,appsettings.jsonに追記。

こちらもなぜか接続文字列が定義されないので追記。

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  // 以下、追記部分
  "ConnectionStrings": {
    "TestDBContext": "接続文字列"
  }
}

3,コンテキストクラスに追記。

なぜか主キーが設定されないので追記。

           modelBuilder.Entity<Account>(entity =>
            {
                entity.ToTable("account");

                // 主キーの指定
                entity.HasKey(e => e.AccountId);

                entity.Property(e => e.AccountId).HasColumnName("account_id");
          }

docs.microsoft.com

C# .net Coreの基本

 

参考書籍

この作者さんの本にも大変お世話になっております。

wings.msn.to

 

 コードファーストでDBアクセス

(非スキャフォールディング)モデル作成→DB反映→コントローラからDBアクセスまでの流れ

 

・プロジェクト作成

プロジェクトの作成でASP.NET Core Web アプリ(Model-View-Controller)」を選ぼう!
ASP.NET Core Web アプリ」という似たのがあるので注意!!!
 
次に
EntityFrameworkCore
EntityFrameworkCore.SqlServer
EntityFrameworkCore.SqlServer.Design(DBファーストの時のみ)
EntityFrameworkCore.Tools
Web.CodeGeneration.Design(スキャルフォールディングの時に要求される)
をNuGetする。
 

・モデルクラス作成

モデルクラス作る。
ルールは下記。
・クラス名はテーブル名と同名であること
・プロパティは対応するテーブル列と同盟であること
・主キーはId、もしくはクラス名+Id。(AccountくらすならAccountId)
namespace WebApplication2.Models
{
public class Account
{
public int Id { get; set; }
public int age { get; set; }
public string name { get; set; }
public string email { get; set; }
public string password { get; set; }
 
}
}
 

・コンテキストクラス作成

コンテキストクラス作る。
モデルクラスをDBに橋渡しする役割。
using Microsoft.EntityFrameworkCore;
namespace WebApplication2.Models
{
//DbContextの継承
public class MyContext:DbContext
{
// コンストラク
public MyContext(DbContextOptions<MyContext> options) : base(options) { }
//モデルクラスへのアクセサー
public DbSet<Account> Account { get; set; }
}
}
 
 

・DB接続文字列を定義する

appsettings.jsonにて定義。
"ConnectionStrings": { "接続名": "Server=サーバー名;Database=DB名~"}
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"MyContext": "Server=(localdb)\mssqllocaldb;Database=WebApplication2(←プロジェクト名);Trusted_Connection=True;MultipleActiveResultSets=true"
}
}
 

・アプリにコンテキストクラスを登録する

Startup.cs
接続文字列とコンテキストクラスを紐付けする。
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddControllersWithViews();
//コンテキストクラスを登録
services.AddDbContext<MyContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("MyContext")));
}
 

マイグレーションを実行する

マイグレーションはモデルクラスを元にDBを作成・変更する仕組み。
ここでは、DBの作成をしている。
ツール→NuGetパッケージマネージャ→パッケージマネージャコンソール
Add-Migration Initial(マイグレーションを追加)
Update-Database (DBに反映)
※注意
表示→SQL Serverオブジェクトエクスプローラーで確認。
なかなか反映されない時はVisualStudioを再起動。
 
rootディレクトリの下にMigrationsディレクトリができる。
これ見ると何やってるかなんとなくわかりそう↓
using Microsoft.EntityFrameworkCore.Migrations;
namespace WebApplication2.Migrations
{
public partial class Initial : Migration
{
//upメソッドでテーブル作成
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Account",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
age = table.Column<int>(type: "int", nullable: false),
name = table.Column<string>(type: "nvarchar(max)", nullable: true),
email = table.Column<string>(type: "nvarchar(max)", nullable: true),
password = table.Column<string>(type: "nvarchar(max)", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Account", x => x.Id);
});
}
//Downメソッドでテーブル削除
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Account");
}
}
}
 

・コントローラーにコンテキストを注入

using Microsoft.AspNetCore.Mvc;
using WebApplication5.Models;
namespace WebApplication5.Controllers
{
public class HelloWorldController : Controller
{
 
private readonly MyContext _context;
//コンストラク
//依存性の注入でコンテキストクラスを取得
public HelloWorldController(MyContext context)
{
this._context = context;
}
//アカウント情報をビューに渡す
public IActionResult List()
{
return View(this._context.Account);
}
}
}
 

・画面の作成

上記コードのListにカーソルを合わせて右クリック
→ビューの追加
→Razorビュー
→ビュー名List・テンプレートEmpty・レイアウトページを使用するにチェック
→追加でこんなんができる↓
List.cshtml
@{
ViewData["Title"] = "List";
}
<h1>List</h1>
↓コードを追加
<!--Accountモデルを宣言-->
@model IEnumerable<WebApplication5.Models.Account>
@{
ViewData["Title"] = "List";
}
<h1>List</h1>
<h2>アカウント情報</h2>
@foreach (var item in Model)
{
<p>@item.Id</p>
<p>@item.age</p>
<p>@item.email</p>
<p>@item.password</p>
}
 

(有スキャフォールディング)モデル作成→DB反映→コントローラからDBアクセスまでの流れ

モデルクラス作成(非スキャフォールディングと同じ)
スキャフォールディング
Controllersフォルダを右クリック
→追加→コントローラー
→EntityFrameworkを使用したビューがあるMVCコントローラ
→モデルクラス選択&データコンテキストクラスの+ボタンクリック
→ビューの生成・スクリプトライブラリの参照・レイアウトページを使用するにチェック
→追加
 
・生成ファイル
  • ~Controller.cs:CRUD機能が入ったコントローラ
  • Index.cshtml:一覧画面のテンプレート
  • Details.cshtml:詳細画面テンプレート
  • Create.cshtml
  • Delete.cshtml
  • Edit.cshtml
  • ~Context.cs:DBとの橋渡し役のコンテキストクラス
  • 接続文字列の定義(appsetteings.json)
  • コンテキストの登録(Startup.cs)
 
これでコンテキストクラス作成・DB接続文字列の定義・コンテキストのアプリへの登録も全部やってくれる!
恐ろしい!
最後にマイグレーション。パッケージマネージャコンソールで。
Add-Migration Initial(マイグレーションを追加)
Update-Database (DBに反映)
 

 

リクエスト送信→受け取り

cshtmlからリクエスト送信

・リンク
<a asp-action="Edit" asp-route-id="@item.Id">Edit</a>
<a asp-action="Details" asp-route-id="@item.Id">Details</a>
<a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
<a asp-action="Delete" asp-route-id="@item.Id">Create</a>
・form
<form asp-action="Create" method="post">
 <input type="text" asp-for="Company">
 asp-for="Company"にするとidとnameがCompanyになる。

コントローラでリクエスト受け取り

アクションメソッド名を同じにするだけ。
public async Task<IActionResult> Edit(int? id){ 処理 }
public async Task<IActionResult> Detail(int? id){  }
public async Task<IActionResult> Delete(int? id){  }
public async Task<IActionResult> Create(int? id){  }
 
formからの受け取り
public async Task<IActionResult> Create(Model company){  }
 引数名をasp-for(name属性)と同じにすると受け取れる。

DBでCRUD操作

検索形

Select
・結果が複数の場合
        // GET: Books/Edit/5
        public async Task<IActionResult> Edit(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }
 
            var book = await _context.Book.FindAsync(id);
            if (book == null)
            {
                return NotFound();
            }
            return View(book);
        }
 
・結果が1つの場合
        // GET: Books/Details/5
        public async Task<IActionResult> Details(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }
 
            var book = await _context.Book
                .FirstOrDefaultAsync(m => m.Id == id); //複数と1つでここが違う
            if (book == null)
            {
                return NotFound();
            }
 
            return View(book);
        }
 

検索条件を複数にする

・FirstOrDefaultAsync(m=>条件式 && 条件式 || 条件式)
条件に合致するデータを1件だけ返す。(複数ヒットしても1件)
mは検索対象のモデル。
FirstOrDefaultAsync(m.Id=>id == id && m.name == name);
 

更新系

更新系の場合は引数をBind()でモデルバインディングするのがポイント。
オーバーポスティング攻撃対策。
 
※モデルバインドとは
その名の通り、モデルクラスにバインド(紐付け)すること。
多分もっと広い用途があるので要調査。
 
Insert文(新規作成)
public async Task<IActionResult> Create([Bind("Id,Title,Price,Publisher,Sample")] Book book)
{
if (ModelState.IsValid)
{
_context.Add(book); // ここでInsert
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
//return RedirectToAction("Index");
}
return View(book);
}
Update文
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Edit(int id, [Bind("Id,Title,Price,Publisher,Sample,RowVersion")] Book book)
        {
中略
                try
                {
                    _context.Update(book); //ここでアップデート
                    await _context.SaveChangesAsync();
                }
 
Delete文
        // POST: Books/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> DeleteConfirmed(int id)
        {
            var book = await _context.Book.FindAsync(id);
            _context.Book.Remove(book); //ここでDELETE
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }

 

 

コントローラのアレコレ

コントローラーからテンプレートの呼び出す時の挙動

return View();
上記のようにパス指定なしでテンプレートを呼び出すと、以下のようにアクションに対応したテンプレートを呼び出そうとします。
/Views/コントローラー名/アクション名.cshtml
 
こんな感じで引数指定すれば同コントローラ内の別アクションメソッドを指定できる。
return View("Hoge");
/Views/コントローラー名/Hoge.cshtml
 

別のコントローラのアクションメソッドを呼びたい時はRedirect

・Redirect(string url)
url:URLをパス指定する。多分Viewsがルートディレクトリ。
 
・RedirectToPage(string pageName)
pageName:cshtmlのファイル名の拡張子が無い名称。
 
・RedirectToAction(String actionName [,string controllerName] [,object Values])
  • actionName:アクションメソッド名
  • controllerName:コントローラ名
  • Values:ルートパラメータ
 
 

モデルクラスでできること色々

表示名とデータ型と検証属性の指定。データ型は指定する効果がよくわからず。
[DisplayName("値段")] //ビューでの表示名を付与
[DataType(DataType.Currency)] //ビューでのデータ型を指定。
[StringLength(20, ErrorMessage = "{0}は{1}文字以内で入力してください。")] //検証属性
String price {get; set;}
 
参考

セッション

・参考サイト
 
 
 
 
Startup.csでセッションの設定をする
public void ConfigureServices(IServiceCollection services)
{
 
//セッションの設定
services.AddDistributedMemoryCache();
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromSeconds(10);
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
});
}
 
public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
//セッションを使う
app.UseSession();
}
 
セッションを使う
// セッションへ値をセット
HttpContext.Session.SetString("key","value");
HttpContext.Session.SetInt32("key2",123);
 
// セッション変数から値を取得
string mystring = HttpContext.Session.GetString("key");
int myint = HttpContext.Session.GetInt32("key2");
 
セッションをビューで表示
@using Microsoft.AspNetCore.Http
 
<div>
<p>@Context.Session.GetString("test")</p>
</div>
 

同時実行制御(トランザクション的なの)

RowVersionというのを使う。
 

コードファーストで同時実行制御

1,モデルクラスにRowVersion列を追加。
[Timestamp]
public byte RowVersion { get; set; }
 
2,Add-Migration→Update-Database
 
3,Edit.cshtmlにRowVersionを追加。
<input type="hidden" asp-for="RowVersion" />
 
4,Controllerで競合検出
if (ModelState.IsValid)
{
try
{
_context.Update(hoge);
await _context.SaveChangesAsync();
 
}
catch (DbUpdateConcurrencyException)
{
 
//ここ↓
ModelState.AddModelError(string.Empty, "競合が検出されました。");
return View(hoge);
}
return ~;
}
 

DBファーストで同時実行制御

SSMSでrowversionを追加。
 
ただし、GUIだとデータ型でrowversion型が存在しない。
 
なのでSQLで打ち込む。
ALTER TABLE tableName ADD
columnName rowversion NULL;
 
 ちなみに上記SQLを打っても、GUI上だとTimestamp型と表示されるが実際にはrowversion型らしい。
 
あとの手順はコードファーストとほぼ一緒。Add-Migration→Update-DatabaseはやらなくてOK。
 
参考サイト

social.msdn.microsoft.com

 

コードファーストで主キーの名前を変える方法

コードファーストだと主キー名が「Id」か「classNameId」しかつけられない。
Companyクラスなら「Id」か「CompanyId」
 
・参考
 
・コンテキストクラスを変更する。
public DbSet<Test> Test { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Test>()
.HasKey(b => b.Test_id) //←こっちがモデルクラスの名前
.HasName("Test_id"); // ←こっちがDBのカラム名
}
 

VisualStudio内のDBで主キー名変更の場合

主キー名を変える場合は一度DBごと消さないとダメ。
手順は
上記の要領でコンテキストクラス変更
→DBを消す
マイグレーションファイルも消す
→Add-Migration
→Update-Database
 

入力チェック(バリデーション)

モデルクラスに検証属性を付与。
[StringLength(20, ErrorMessage = "{0}は{1}文字以内で入力してください。")]
public string TeamName { get; set; }
 
ビューでエラメッセージを表示。
asp-validation-summary="ModelOnly":モデル全体に関わるエラーだけを表示する。
asp-validation-for="CharacterName":CharacterNameに関するエラーを表示。
Hoge.cshtml
<div asp-validation-summary="ModelOnly" class="text-danger"></div> //ModelOnlyはモデル全体に関わるエラーだけを表示する。
<span asp-validation-for="CharacterName" class="text-danger"></span> //CharacterNameに関するエラーを表示。
 
//入力チェックのためのJavaScriptライブラリのインポート。
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
 
・参考
 

ルーティング

pattern:”{controller}/{action}/{id}”
  • {controller}にはコントローラ名
    • {controller=Home}の「=」はこのパラメータの既定値をHomeにする。
  • {action}にはメソッド名(アクションメソッド)
    • {action=Index}の「=」はこのパラメータの既定値をIndexにする。
  • {id}にはメソッドに渡す値
    • /{id?}の「?」はこのパラメータを省略可にする。
 
Startup.cs
```
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
```
 

Razor

Razorテンプレートによる変数出力・処理の実行の基本

・サーバー側
ViewBag.変数名=値
ViewData[“変数名”]=値
 
```
public IActionResult Greet()
{
ViewBag.Message = "こんにちは、世界!";
 
return View();
}
 
```
 
・画面側
@・・・は出力。
@{・・・}はコードブロック。実行。出力するわけではない。
 
@{
ViewData["Title"] = "Greet";
}
 
<h1>Greet</h1>
<p>@ViewBag.Message</p>
 

Razor側でモデルクラスをインポート・取り出し

<!- Bookモデルを参照する></!->
@model IEnumerable<QuickMaster.Models.Book>
 
// 取り出し
@foreach (var item in Model)
{
<tr>
<td>@item.Title</td>
<td>@item.Price</td>
<td>@item.Publisher</td>
<td>@item.Sample</td>
</tr>
}
 

ヘルパーメソッド一覧

  • ViewResult View():テンプレートに基づいてページ出力
  • ContentResutl Content(string content):テキスト出力
  • RedirectResult Redirect(string url):指定されたパスに移動(リダイレクト)
  • RedairectToAction() 指定されたアクションに移動(リダイレクト)
  • File():指定されたバイト配列をファイルとして出力
  • NotFound();404エラーを出力
 

よく使うビューヘルパー/タグヘルパー一覧

ビューヘルパー一覧
  • @foreach
  • @Html.Displayfor データ方に応じて出力を変化させる。
  • @Html.DisplayNamefor プロパティ名↓を表示する。列名のタイトル表示に使う。
 
タグヘルパー一覧
<form asp-controller="">:コントローラ名に関連づいたフォーム
<form asp-action="">:アクション名に関連づいたフォーム
<a asp-controller="">:コントローラ名に関連づいたリンク
<input asp-for="">:入力タグヘルパー 例:asp-for="company"にするとid="company" name="company"になる。
<select asp-for"">:セレクトボックス
<textarea asp-for="">:テキストエリア
<label asp-for="">:ラベル
<span asp-valication-for="">:入力エラー。個別のプロパティ
<div asp-validation-summary="">入威力エラー。モデル全体。
 
公式:組み込みタグヘルパー一覧↓
 
ASP.NET Core MVC の Razor で使える Tag Helpers のメモ書き
 

動的なSelectボックスの使い方

・参考サイト
 
サーバ側でセレクトボックスに渡す値を用意。
SelectList()を使う。
--------------------------
SelectList(IEnumerable items, string dataValueField, string dataTextField, object selectedValue)
items:列挙可能なもの。コレクションとかDBの検索結果をそのままぶち込める。
dataValueField:valueに入る値。
dataTextField:画面に表示される値。
selectedValue;初期値。
-------------------------
// 画面にはTeamNameが表示されるが、valueにはTeamIdが入る。
ViewData["TeamId"] = new SelectList(_context.Teams, "TeamId", "TeamName", character.TeamId);
return View(character);
 
ビューでセレクトボックスを表示。
<select asp-for="TeamId" class="form-control" asp-items="ViewBag.TeamId"></select>
 

部分ビュー

Sharedディレクトリに_bubunView.cshtmlを作成。
@using Microsoft.AspNetCore.Http
<div>
<p>@Context.Session.GetString("test")</p>
</div>
 
cshtmlに表示。
<h1>Create</h1>
<partial name="_bubunView" />
<h4>Team</h4>
 

SQL Serverの接続文字列の確認方法

・最初にメモっておく方法
SQL Serverをインストールした時に1回だけ表示されるのでメモっておく。

 

・あとから調べる方法
zebratch.blog.ss-blog.jp

 

まずサーバー名を調べる。
SQL Server Management Studioでデータベース右クリック→プロパティ→接続のプロパティの表示で見れる。
サーバー名が自分のPC名になってたら接続文字列のサーバー名はlocalhostにする。

 

次にvisual studioでデータベース接続をする。
visual studio2019ではツール→データベースへの接続で、サーバー名とデータベース名の入力だけでOK。
接続できたらDBを右クリック→プロパティで接続文字列を見れる。

 

私の環境では下記。

上が最初にメモっておいたやつ。下が後から調べたやつ

Server=localhost\SQLEXPRESS;Database=DB名;Trusted_Connection=True;
Data Source=localhost\SQLEXPRESS;Initial Catalog=DB名;Integrated Security=True;

 

もっと簡単な方法ないのかな?

非同期処理とマルチスレッドの違い

 

結論

同期処理と非同期処理の違い=待つか待たないか。
シングルスレッドとマルチスレッドの違い=単線か複線か。

 

同期処理

今の処理が終わるまで待つ。

次の処理は始まらない。

 

非同期処理

今の処理で待ち時間ができたら、次の処理を始める。

同時に実行しているわけではなく、待ってる間に次を始める

 

AさんがBさんに仕事を渡す

→Bさん仕事中

→AさんはBさんの仕事が終了するまで進められない

→Aさんは別の仕事を見つけてやり始める

 

ぼーーっとするくらいなら次にいこうねって感じ。

シングルスレッドで実装可能。

これが非同期処理。

 

シングルスレッド

同時実行不可。

 

マルチスレッド

同時実行可能。

 

キューとは

 順番待ち行列のこと。

1個ずつ処理されていく。

 

非同期処理の例

JavaScriptとHTTP

JavaScriptでHTTPにリクエスト送った。

HTTPからレスポンス返ってくるまで暇。

じゃあJavaScriptは別のことやるか。

HTTPから完了通知来たらキューに入れよ。

 

・CPUとプリンタ

CPUは高速だがプリンタは低速。

CPUからプリンタに指令を出した後、CPUはやることがない。

だから次の処理に移行する。

プリンタからの完了通知は割り込み信号によって検知する。

信号きたらキューに入る。

 

okwave.jp

setTimeoutは勘違いしやすい

function doSample() {
setTimeout(onFirst, 2000);
setTimeout(onSecond, 4000);
 
function onFirst() {
console.log("first")
}
 
function onSecond() {
console.log("second")
}
}
doSample();

上記コードは合計4秒で完了する。

シングルスレッドなら2+4で合計6秒じゃないの?と思っていた。

 

だけど、setTimeoutはx秒後に処理を始めるという登録をするだけ。

なので処理は一瞬で完了するんだって。

 

seTimeout1実行→setTimeout2実行→2秒後に完了通知→4秒後に完了通知

ということ。

teratail.com

setTimeoutの疑問

待ち時間をカウントして完了通知を送る、という処理はJavaScriptではない何かがやっているということになる。

一体それはなんだろう?

 

参考↓

coliss.com

上記サイトによるとsetTimeoutは指定秒後に実行ではなく、指定秒後にキューに送るということらしい。

また、待ち時間のカウントはWebAPIがやっているらしい。

 

非同期処理で勘違いしていたところ

HTTPレスポンスが返ってくるまで別の処理をやる、みたいなのが多くて、これってリクエスト送る→レスポンス受け取るっていう処理と別の処理を同時にやっているんだからマルチスレッドじゃないか!みたいに思っていたがそんなことはなかった。

 

レスポンスを返してくるのはHTTPのお仕事であってJavaScriptではないので、その間にJavaScriptは別のことを1つやっているだけだよね。

 

JavaScriptでは必ず同期処理の完了後に非同期処理が完了するのはなぜか?

ここちゃんと調べてないので私の予想です。
同期処理1
非同期処理1
非同期処理2
同期処理1
----------
結果
同期処理1完了
同期処理2完了
非同期処理1完了
非同期処理2完了
--------
これは
  1. 同期処理1が開始&完了
  2. 非同期処理1が開始
  3. 非同期処理1完了後の処理1がキューに入る
  4. 非同期処理2が開始
  5. 非同期処理2完了後の処理2がキューに入る
  6. 同期処理2が開始&完了
  7. 非同期処理1の完了通知&完了
  8. 非同期処理2の完了通知&完了
ということなんじゃないかなと思う。
ちなみに最後の非同期処理1・2の完了は順不同です。
完了通知が来た順に完了するので。
 
コードにするとこう↓
console.log(1);
setTimeout(first,1000);
setTimeout(second,500);
console.log(2);
 
function first() {
console.log("first");
}
 
function second() {
console.log("second");
}
-------------
1
2
second
first
-------------