okinawa

IT勉強メモ

テーブル結合とViewModel

・参考

複雑なクエリ演算子 - EF Core | Microsoft Docs

ViewModelの作成

ここで言うViewModelとはテーブル結合の結果表示用のモデルクラス。

public class Blog
{
public int BlogId { get; set; }
public string Url { 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; } //外部キー
}

上記のBlogテーブルとPostテーブルの結合結果表示用のViewModel↓

2つのモデルクラスをがっちゃんこするだけ。

public class BlogPostViewModel
{
public int BlogId { get; set; }
public string Url { get; set; }
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
}

テーブル結合

var query = from blog in context.Set<Blog>()
            join post in context.Set<Post>()
                on blog.BlogId equals post.BlogId
            select new BlogPostViewModel{ BlogId = blog.BlogId, Url = blog.Url, PostId = post.PostId, Title = post.Title, Content = post.Content };

JavaScriptメモ

参考

jsprimer.net

基本

ECMAScriptJavaScriptの中のどの実行環境でも共通する部分。

"use strict";基本的には常に使う。

宣言

const 再代入できない変数。厳密には定数ではないらしい。

let 再代入可能な変数。初期値を指定しない変数も定義できます。 初期値が指定されなかった変数はデフォルト値としてundefinedという値で初期化されます。

varは使わない。同じ名前の変数名を定義できたり、巻き上げやら色々問題があるらしい。

varが危険な理由。宣言だけがスコープの先頭に巻き上げられ、代入はその位置のままだから。

データ型

int/doubleがない。数字は基本Number型。

JavaScriptのデータ型はプリミティブ型とオブジェクト型の2つ。ラッパークラスもオブジェクト。

NaNとはNot a Numberのこと。Number型と互換性のない性質のデータをNumber型へ変換した結果はNaNとなります。

演算子

** べき乗演算子

=== 厳密等価演算子 同じ参照値かを判定

== 等価演算子 値が同じかを判定。型が違くても等価判定!使わないでおこう。

// 文字列を数値に変換してから比較
console.log(1 == "1"); // => true

例外的に、等価演算子(==)が使われるケースとして、nullとundefinedの比較があります。

文字列

シングルクォートとダブルクォートは全く同じ。

テンプレートリテラルはバッククォート。改行も反映される。

// 改行も反映される
contst str =
 `名前は${name}です。
年齢は${age}です。`;

オブジェクト

オブジェクトのプロパティの追加

// `key`プロパティを追加して値を代入
obj.key = "value";

オブジェクトのプロパティの削除

// プロパティの削除
delete obj.key;

配列は可変長。あとから要素足せる。オブジェクトと一緒。array.push(1)など。

例外処理

console.errorでスタックトレース

非同期処理の例外処理

tryブロックはそのブロック内で発生した例外をキャッチする構文です。 しかし、非同期処理は同期処理の後に完了します。非同期処理が実行されて例外を投げるのは、すべての同期処理が終わった後となります。つまりcatchできない。

エラーファーストコールバック。非同期処理中に発生した例外を扱う仕様。

fs.readFile("./example.txt", (error, data) => {
    if (error) {
        // 読み込み中にエラーが発生しました
    } else {
        // データを読み込むことができました
    }
});

暗黙的な型変換

JavaScriptでは、エラーが発生するのではなく、暗黙的な型変換が行われてしまうケースが多くあります。

暗黙的に変換が行われた場合、プログラムは例外を投げずに処理が進むため、バグの発見が難しくなります。 このように、暗黙的な型変換はできる限り避けるべき挙動です。

// 暗黙的な型変換が行われ、数値の加算として計算される
1 + true; // => 2

関数

関数を変数に代入

次のコードでは、定義したfn関数をmyFunc変数へ代入してから、呼び出しています。

function fn() {
    console.log("fnが呼び出されました");
}
// 関数`fn`を`myFunc`変数に代入している
const myFunc = fn;
myFunc();

匿名関数

名前を持たない関数を変数に代入できます。

// 関数式は変数名で参照できるため、"関数名"を省略できる
const 変数名 = function() {
};
// 関数宣言では"関数名"は省略できない
function 関数名() {
}

その他

JavaScriptは静的スコープ。ある変数がどの値を参照するかは実行前(静的)に決まる。

クロージャー(関数閉包)とは。クロージャーは「静的スコープ」と「参照され続けている変数のデータが保持される」という2つの性質によって成り立っています。

クラス宣言。

class MyClass { }

getter setter

class クラス {
    // getter
    get プロパティ名() {
        return 値;
    }
    // setter
    set プロパティ名(仮引数) {
        // setterの処理
    }
}
const インスタンス = new クラス();
インスタンス.プロパティ名; // getterが呼び出される
インスタンス.プロパティ名 = 値; // setterが呼び出される

コントローラの戻り値型(IActionResult型)の一覧

・参考

docs.microsoft.com

 

一部ですが一覧。

 

ContentResult:生のテキストコンテンツをブラウザーに送信する。

EmptyResult:ブラウザーにコンテンツを送信しない。

FileContentResult:ファイルの内容をブラウザーに送信汁。ファイルの内容はバイト配列。

FileStreamResult:ファイルの内容をブラウザに送信する。ファイルの内容はStreamオブジェクト。

LocalRedirectResult:HTTP302をブラウザに送信することで、現在のサイトに対してローカルなURLにリダイレクトさせる。指定できるのは相対URLのみ。

JsonResult:JSON文字列をブラウザに送信。

NotFoundResult:404を返す。

PartialViewResult:ページビューの一部を表すHTMLコンテンツをブラウザに送信。

PhysicalFileResult:ファイル内容をブラウザに送信。ファイルはパスとコンテンツタイプによって識別される。

RedirectResult:HTTP302をブラウザに送信することで、特定のURLへリダイレクト。

RedirectToActionResult:RedirectResult同様。URLはアクションとコントローラーのペアに基づいて識別。

RedirectToRouteResult:RedirectResultと同様。URLはルート名に基づく。

StatusCodeResult:指定されたステータスコードを返す。

ViewComponentResult:ビューコンポーネントから取り出したHTMLコンテンツをブラウザに送信。

ViewResult:完全なページビューを表すHTMLコンテンツをブラウザに送信。

VirtualFileResult:ファイルの内容をブラウザに送信。ファイルはその仮想パスに基づいて識別。

.net Core コントローラにフィルターを噛ます

・参考書籍

「プログラミング ASP.NET CORE」のP103 カスタムヘッダー

モデル↓

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;

namespace TeamMember.Models
{
    public class FilterTest : ActionFilterAttribute
    {
        // アクションメソッド発動後にフィルター作動する時はExecuted
        public override void OnActionExecuted(ActionExecutedContext context)
     { 
            //セッションの取得
            context.HttpContext.Session.GetString("name");
            base.OnActionExecuted(context);
        }

        // アクションメソッド発動前にフィルター作動する時はExecuting
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            DateTime date = DateTime.Now;

            base.OnActionExecuting(context);
        }
    }
}

コントローラにカスタムヘッダーを付ける↓

    [FilterTest] //コントローラに付けると全てのアクションメソッドにフィルターかかる 
    public class CharactersController : Controller
    {
 
        [FilterTest] //アクションメソッドに付けるとここだけにフィルターかかる
        public IActionResult Index() {
            return View();
        }
    }

.net core 自作のバリデーション

  

モデルクラスに記述するバージョン

using System. Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
 
// IValidatableObject インター フェイス を 実装
public class Book : IValidatableObject {
 
public int Id {get; set;}
public string Cat {get; set;}
 
// 検証 ルール の 実体
public IEnumerable < ValidationResult > Validate( ValidationContext validationContext)
{ if( this.Cat != "猫") {
 
// モデル全体エラー
yield return new ValidationResult( "Catは猫です。");
 
// Catプロパティにエラー表示するならこう
yield return new ValidationResult( "Catは猫です。", new { "Cat" });
 
} } }
 

コントローラに記述するバージョン

・参考

ASP.NET Core: エラーメッセージ一覧のカスタマイズ

public IActionResult Edit(int id)
{
if (id != character.CharacterId)
{
// モデル全体エラー表示するならこう
ModelState.AddModelError(string.Empty, "IDが見つからないよ");
 
// Catプロパティにエラー表示するならこう
ModelState.AddModelError("Cat", "IDが見つからないよ");
return View();
}
}

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

 

コードファースト

※下記の方法だと上手く行かなかった

なので、直接DBで外部キーを設定

→モデルクラスを下記と同じように外部キー・ナビゲーションプロパティを追加(ナビゲーションプロパティはいらなかった気もする。よく覚えておらず)

→Add-migrationもupdate-databaseもやらずで完了

 

 

以下が、上手く行かなかった方法↓

・参考

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の指定を「はい」にする。