狛ログ

2021年4月23日金曜日

SQL Server のデータ移行方法と特徴について。

4月 23, 2021

オフィス狛 技術部のJoeです。

担当したプロジェクトで、SQL Serverのデータを移行する要件がありました。
データの移行方法を調べてみると色々な方法がありましたので、
いくつかの移行方法と、その特徴をまとめてみました。

1.デタッチとアタッチ

【主な手順】
移行元でデタッチ
-> データファイルとトランザクションログファイルを移行先にコピー
-> 移行先でデータファイルをアタッチ

【特徴】
・データファイルとトランザクションログファイル自体を移行します。
 (実質、データベースの移行になります)
・デタッチすると、DBが参照できなくなります。
 (アタッチし直せば、また参照可能になります)
・SQL Serverのバージョンアップにも対応しています。
・デタッチには、いくつかの制限事項があります。(下記の「データベースのデタッチ」を参照)
 https://docs.microsoft.com/ja-jp/sql/relational-databases/databases/database-detach-and-attach-sql-server?view=sql-server-ver15
・後述する移行方法と比較すると、移行に掛かる時間は最も短いです。

2.バックアップとリストア

【主な手順】
移行元でバックアップ
-> バックアップファイルを移行先にコピー
-> 移行先でリストア

【特徴】
・バックアップファイルを作成して移行します。
 (実質、データベースの移行になります)
・DBを停止しなくても移行可能です。
・SQL Serverのバージョンアップにも対応しています。
・リストアの際に、DBとデータファイル名を変更することで、DB名の変更が可能です。
 同じインスタンス内であれば、DB名を変更することで、複製することもできます。

3.ExportとImport

【主な手順】
Data Source設定 -> Destination設定
 ※SQL Server Management Studio の「Import and Export Wizard」を利用した場合です

【特徴】
・移行先から直接移行先へデータを移行可能です。
・DBを停止しなくても移行可能です。
・Destinationに「Flat File Destination」を指定すれば、移行元のデータをファイル化することができます。
 ただし、テーブル単位でしかファイルを作成できませんでした。
・「Import and Export Wizard」は機能が多く便利なのですが、逆に使いこなすことが難しいと感じました。
一度、「Import and Export Wizard」でデータ移行を試してみたところ、下記エラーが発生しました。
Error 0xc02020f4: Data Flow Task 1: The column "カラム名" cannot be processed because more than one code page (932 and 1252) are specified for it.
こちらは、Import と Export するテーブルの照合順序(Collation)が異なっていたことが原因でしたが、
メッセージから原因が予測できず、解決するのに少し時間が掛かってしましました。

4.スクリプト作成と実行

【主な手順】
移行元でスクリプト作成
-> スクリプトコピー
-> 移行先でスクリプト実行
 ※SQL Server Management Studio の「Generate and Publish Scripts」を利用した場合です

【特徴】
・スクリプトファイルを作成します。
・DBを停止しなくても移行可能です。
・スクリプトファイルは、スキーマのみ(CREATE DATABASE、CREATE TABLE 等)、
 データのみ(INSERT)や、スキーマとデータ両方など、用途によって作成できます。
・SQLが直接書かれたファイルなので、大量データの場合はファイル容量が大きくなり、
 スクリプトを実行する際も、時間が掛かってしまいます。
・逆に、SQLを直接修正(スキーマの変更や、データの編集)できるので、
 データ量が少ない場合は扱い易いです。


データ移行は、移行時のシステムの稼働状態やデータ量などによって、
適切な移行方法を選定する必要がありますので、上記の特徴が何かお役に立てれば幸いです。

2021年3月30日火曜日

Swift・UIBarButtonItemのtitleを変更する。

3月 30, 2021

こんにちは、オフィス狛 技術部のpinoです。


この度、初めてiOSアプリの開発に携わることができました。

まだまだ勉強中の身ですが、今回は「UIBarbuttonItemのtitleを変更する方法」について紹介したいと思います!


方法

早速ですが、UIBarbuttonItemのtitle変更方法です。

    private func setBarButtonItem() {
        // UIBarbuttonItemのactionを設定
        let button = UIBarButtonItem(title: "タイトル", style: .plain, target: self, action: #selector(self.buttonTapped(_:)))
    }

    @objc func buttonTapped(_ sender: UIBarButtonItem) {
        // 変更後のタイトルを設定
        sender.title = "変更後のタイトル"
    }

タップ時の処理でUIBarButtonItemを引数にとって、
(仮引数名がsenderの場合)sender.title = "hoge"としてあげることでtitleの変更ができます。


...思いのほか、すごく簡単でしたね!
せっかくなので、ここからはこのtitle変更を活かしたものを作ってみたいと思います。


作るもの

以下のようなものを作っていきます。

  1. ・画面真ん中にTextFieldを配置
  2. ・TextField押下でキーボード表示。このキーボードの上にUIToolbarを配置
  3. ・UIToolbar上に並んでいるUIBarButtonItemタップで、キーボードタイプを切り替え

UIBarbuttonItemのtitle変更は、「UIBarButtonItemタップ」で発火するようにしてみます。


準備

Interfaceに「Storyboard」を選択して、プロジェクトを作成します。


画面真ん中にTextFieldを置いて、Keyboard Typeを「Number Pad」にしておきます。


ViewControllerで、TextFieldにUIToolbarを追加します。
ViewController.swift
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var sampleTextField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()
        self.setToolbar()
    }
    
    private func setToolbar() {

        let toolbar = UIToolbar()
        toolbar.sizeToFit()

        let inputSwitchButton = UIBarButtonItem(title: "英数字入力に切り替え", style: .plain, target: self, action: nil)
        let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)

        toolbar.items = [space, inputSwitchButton]

        self.sampleTextField.inputAccessoryView = toolbar
    }
}


ここまでで、「英数字入力に切り替え」というtitleのUIBarButtonItemが表示されるようになりました。


UIBarbuttonItemのtitle変更

UIBarButtonItemタップ時の処理を定義します。

ViewController.swift
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var sampleTextField: UITextField!
    // 中略
    private func setToolbar() {

        let toolbar = UIToolbar()
        toolbar.sizeToFit()

        let inputSwitchButton = UIBarButtonItem(title: "英数字入力に切り替え", style: .plain, target: self, action: #selector(self.inputSwitchButtonTapped(_:)))  // 🍀変更
        let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)

        toolbar.items = [space, inputSwitchButton]

        self.sampleTextField.inputAccessoryView = toolbar
    }

    // 🍀追加
    @objc func inputSwitchButtonTapped(_ sender: UIBarButtonItem) { 
        sender.title = "数字入力に切り替え"
    }
}

inputSwitchButtonTapped()を定義して、その中でtitleの変更を行うようにしました。

さらに、inputSwitchButtonの#selectorに inputSwitchButtonTapped()を設定することで、
ボタンタップ時にtitleが「数字入力に切り替え」へと変更されるようになります。

ここまでで、実際の動きは以下のようになります。

1回タップした後は、特に変化がありませんね。

今回はtitleと一緒にKeyboard Typeも変更したいので、inputSwitchButtonTapped()を以下のように修正します。

    @objc func inputSwitchButtonTapped(_ sender: UIBarButtonItem) {
        // キーボードが表示されたままだとKeyboard Typeの変更が反映されないのでフォーカスを外す
        self.sampleTextField.resignFirstResponder()
        
        // 🍀以下の分岐を追加
        if self.sampleTextField.keyboardType == .numberPad {
            sender.title = "数字入力に切り替え"
            self.sampleTextField.keyboardType = .namePhonePad
        } else if self.sampleTextField.keyboardType == .namePhonePad {
            sender.title = "英数字入力に切り替え"
            self.sampleTextField.keyboardType = .numberPad
        }
        
        // Keyboard Typeを切り替えた後に再度フォーカスする
        self.sampleTextField.becomeFirstResponder()
    }

(フォーカスのつけ外しについては、コメントの通りです)
現在のKeyboard Typeを判定して、titleとKeyboard Typeが切り替わるようにしました。

完成!

完成形は、以下のようになります。




以上、UIBarbuttonItemのtitleを変更する方法について紹介しました。
参考になるとうれしいです。

2021年3月29日月曜日

windows.openを使用した時に、iOSのSafariにて別タブでファイルを開けない場合の対処法。

3月 29, 2021

オフィス狛 技術部のmmm(むー)です。

タイトルの通りですが、windows.open()を使用した際にiOSのSafariにて別タブでファイルを開くことができなかったため、その対処法を書きます。

業務でしたかったこと
・フロント(Angular)にて、リンクを押下した後PDFを別タブで開く
 1. リンクを押下後、APIを呼ぶ
 2. API(Express)で、S3にあるPDFデータ(Blob)をレスポンスする
 3. フロントにてAPIからのレスポンスを取得した後、別タブを開きPDFを表示する

問題点
・iOS(Safari)だけリンクを押しても何も反応しない
・PCブラウザ(Chrome、 Firefox、 Sarfari)やiOSブラウザ(Chrome)はリンク押下後に別タブでPDFを開くことができる

原因
・Safariでは、非同期処理内でwindows.opon()を実行すると呼び出しをブロックするため
observable.subscribe(downloadData => {
	  const blob = new Blob([downloadData], { type: 'application/pdf' });
	  const fileURL = window.URL.createObjectURL(blob);
    window.open(fileURL, '_blank');
})

解決方法
・非同期処理が始まる前に、windows.open() を実行するように変更する
this.windowReference = window.open();  // <- 🌟変更

observable.subscribe(downloadData => {
	  const blob = new Blob([downloadData], { type: 'application/pdf' });
	  const fileURL = window.URL.createObjectURL(blob);
    this.windowReference.location = fileURL;  // <- 🌟変更
})

その他
・iOSのSafariはデフォルトの設定で、ポップアップブロックがONになっているので、OFFにすることで開けるようになります。
・ただ、別タブで開くか確認するポップアップが表示されますし、デフォルトはONになっています。
設定変更方法:iPhoneの設定 > Safari > ポップアップブロックをOFF

以上となります。
同じようにはまった方の参考になりましたら、幸いです🍭

2021年1月22日金曜日

WindowsでDockerを利用してDynamoDBサーバーをたちあげる時の注意点。

1月 22, 2021
オフィス狛 技術部のHammarです。

先日「WindowsでDockerを利用してMySQLサーバーを立てる場合の注意点」でも投稿しましたが、WindowsはDockerをVirtualBox経由で起動させているため、Macで起動する場合とは違い、うまく動かない部分があります。
今回は、WindowsでDockerをつかってDynamoDBサーバーをたちあげる時の注意点を記載しようと思います。

※今回DynamoDBはAWSのDynamoDB Localというツールを利用します。

前回投稿した時と同じようにDockerの起動にはdocker-compose.ymlを利用していきます。
docker-compose.ymlには以下のようにDynamoDBの接続設定を記載します。
※今回DBの記述がメインとなるので、API、DB側の記述は割愛します。

version: '3'
services:
  api:
    build:・・・
    ・・・
  db:
    build:・・・
    ・・・
  dynamodb:
    image: amazon/dynamodb-local:latest
    container_name: elps-client-dynamodb
    command: -jar DynamoDBLocal.jar -sharedDb -dbPath . -optimizeDbBeforeStartup
    ports:
      - "8000:8000"

前回同様上記のように書いて、あとは通常通り上記ymlを使ってDocker起動するだけです。
で、上記方法で、またまたMacでは上手くいくのですが、Windowsではなぜかうまくいきません。
起動はうまくできるのですが、設定したDynamoDBに接続ができないのです。😢

で、またいろいろ調べていくと、やっぱり今回もVirtualBox経由での起動が問題を引き起こしているようでした。。。
今回DynamoDBの接続ポートに8000を指定しているのですが、これはホストマシンのlocalhostで接続しに行きます。
ただ、DockerはVirtualBoxで起動しているため、VirtualBox側の設定でポートフォワーディングが必要なようです。

VirtualBoxのDynamoDBのポートフォワード設定方法

①まずVirtualBoxの「設定」ウィンドウから下記のように「ネットワーク」→「ポートフォワーディング」ボタンを押下します。


②ポートフォワーディングルールの画面の右側の+ボタンを押下して、今回のDynamoDBのポート8000を追加して、「OK」ボタンを押下します。


上記完了後、NoSQL Workbench等のツールや、AWS CLI等を利用してDynamoDBに繋がっているか確認できればOKです。
WindowsユーザーでDockerかつDynamoDBを使う場合には、これ結構ハマりポイントだと思うので、ご参考になれば幸いです。

アピアランスで文字の周りに少し大きい枠線をつくる。

1月 22, 2021


こんにちは、オフィス狛 デザイン部のSatoです。


アピアランスで線を二つ作ると文字から少し離れた所に枠線が引けますが、文字と枠線の間の背景を透かしたい時に困ってしまいました。

調べてみてもなかなか当てはまるチュートリアルが見つからないですし、分割して背景色部分を消したら修正が大変になるので困りました。
しかし、アピアランスの線に効果をかけていくと「枠線の間が透明な枠線」が作れる事に気づいたので、今回はその方法を解説していこうと思います。


まずテキストを用意します。文字色やフォントなどは後から変更する事ができます。

アピアランスタブの下にある新規線を追加ボタンをクリックして線を追加します。文字と同じ色なのでわかりにくいですが枠線が文字の周りにできました。

追加した線を選択し、アピアランスタブの下にある効果ボタンをクリックします。
「パス」→「パスのオフセット」を設定するとパスのオフセットの設定画面が表示されます。

「オフセット」は文字から枠線の幅になるので好きな数値を入力します。
「角の形状」は今回は「ラウンド」を選択します。
プレビューを見て調整した後、OKボタンを押します。


離れた所に枠線はできましたが一文字一文字個別で囲われているので読みにくいですね。


追加した線を選択し、アピアランスタブの下にある効果ボタンを再度クリックします。
「パスファインダー」→「追加」を設定します。
枠が繋がりました!
枠線の幅や太さ、文字の調整などが簡単にできるので状況に応じて調整をしてください。




今回紹介した方法で作ったテキストをアピアランスで線を二つ作ったテキストと一緒にグラデーション背景の上に配置してみました。


今回ご紹介した方法で枠線を引いたテキストは、背景がないので枠線と文字の間にグラデーションが透けています!

アピランスは色々な事が出来すぎてなかなか使いこなす事が難しいですが、他のデザイナーの方が公開しているアピアランスを使ったチュートリアルを見ていると作業効率化に役立ちそうなので、これからもっとアピアランス機能を活用せねばと感じました。

2021年1月8日金曜日

2021年オフィス狛の年賀状の制作秘話。

1月 08, 2021

新年あけましておめでとうございます。オフィス狛 デザイン部のSatoです。
今年もどうぞよろしくお願いいたします。
2020年はレジャーや里帰りになかなか行けなかったり、慣れないリモートワークなどで大変な一年でしたね……。
一日でも早く安心して過ごせるようになることを願うばかりです。

デザイン部の年明け初めての記事ですので去年同様、今年の年賀状のおはなしをしようと思います。
↓去年の年賀状の記事です。

2021年の年賀状はこちら!
前年同様、弊社サイトやSNSなどのアイコンなどで登場している狛犬ちゃん(社内ではよく「こまちゃん」と呼ばれています)がホルスタインのコスプレをして牛乳にしがみついているポップなイラストです。

2020年に姿を描くことでご利益があるという言い伝えがあると話題になったアマビエを描いてみました。
こまちゃんの牛のコスプレも、災害が起こる前に突然現れ予言するという言い伝えがあり、絵図は厄除のお守りになると言われている体は牛で顔は人間の妖怪「」に偶然にも似ているので、ご利益があるかもしれませんね。件と違って体が牛で顔が犬ですがご利益があると信じたいです。
……こまちゃん自体、コスプレしなくても厄除モチーフなのをうっかり忘れていました。



今年は実際に年賀状にした案がでるまでは無難なラフを描いていました。
左のラフの牛は結構好きなんですが無難すぎたかもしれません。

好きなイラストレーターの方が販売している今年用の年賀状に牛乳瓶を持ち上げる牛…という絵のパターンがあり「確かに牛乳も牛モチーフだ!」と気付き、その年賀状を参考にし右の牛きぐるみこまちゃんを牛乳に抱きつかせた絵を試しに描いた所、いい感じになったのでその絵を清書することに決めました。


完成したものには使いませんでしたが、最初上部分の波打つ牛乳のような部分は最初はこちらの液体が垂れるアピアランスのチュートリアルを参考にして牛乳上からダバーっと流れている風にしてみたのですが、私の使い方が悪かったのか少しホラーに見える…と他の社員に指摘され波打つような線に変更しました。



いつか液体が垂れるアピアランスを使いこなしてお洒落に見えるものが作りたいです…!
今年も前進できるよう頑張ります。

2020年12月30日水曜日

Angular・Componentのタグにclassを付与したい【HostBinding】

12月 30, 2020

こんにちは、オフィス狛 技術部のpinoです。

早速ですが、皆さんはAngularをやっていて「コンポーネントのタグに直接classを付与したいんだけどなぁ....。」と思った経験はないでしょうか。

今回は、そんな時に使える @HostBinding についてご紹介したいと思います!

準備

まずは、コンポーネントを用意します。
app.component.html(親コンポーネント)
<header class="header">
  <section class="header__about">
    <h1 class="header__title">@HostBinding Sample</h1>
    <p class="header__lead">動作確認用のサンプルです</p>
  </section>
  <nav class="header-nav">
    <ul class="header-nav__list">
      <app-list-item *ngFor="let name of names" [name]="name"></app-list-item>
    </ul>
  </nav>
</header>

list-item.component.html
<li class="header-nav__item">
  <input type="checkbox" />{{ name }}
</li>
list-item.component.css
.header-nav__item {
  width: 120px;
  height: 64px;
  padding-left: 32px;
  line-height: 64px;
}
list-item.component.ts
import { Component, Input, OnInit } from '@angular/core';

@Component({
  selector: 'app-list-item',
  templateUrl: './list-item.component.html',
  styleUrls: ['./list-item.component.scss']
})
export class ListItemComponent implements OnInit {
  @Input() name: string;

  constructor() { }

  ngOnInit(): void {
  }
}
ビルド後のイメージ

色味がなく、シンプルで寂しい印象です。
ここから、実際にHostBindingを使ってclassを付与してみたいと思います。

HostBindingの使い方

使い方は

1. コンポーネントのタグにclassを付与する
2. 上記1に加えて、動的にclassの付け外しをする

と、主に2つあります。

まずは、1. コンポーネントのタグにclassを付与するについてです。
こちらは、大きく2通りの書き方ができます。
list-item.component.css
import { Component, HostBinding, Input, OnInit } from '@angular/core';  // HostBinding を追加

@Component({
  selector: 'app-list-item',
  templateUrl: './list-item.component.html',
  styleUrls: ['./list-item.component.scss']
})
export class ListItemComponent implements OnInit {
  @HostBinding('class') listItem = 'list-item';  // ①
  @HostBinding('class.first') first = true;  // ②

  @Input() name: string;

  constructor() { }

  ngOnInit(): void {
  }
}

ポイントは、@HostBinding()の、()の中です。
①は、「'class'」のみ指定して、なんのclassを付与するかは変数の値が使用されるパターンです。
値部分に定数を使えば、ロジック側にテンプレートの情報をベタ書きすることも避けられますね。
固定のclassであればこれで十分そうです。

②は、「'class.first'」と付与するclass名まで指定するパターンです。
この場合は、後に続いている値がtrueであれば付与、falseであれば付与しない、ということになります。
(※真偽値を固定で設定したい場合は、「@HostBinding('class.first') readonly first = true;」 といった具合に、readonlyをつけるなどの対策が考えられます。)

また、HostBindingの話とはすこし逸れますが、コンポーネントのタグに使用するclassは
グローバルである(style.cssに記述されている等)か、:hostメタデータを使用する必要があります。

今回は、自コンポーネントのCSSに背景色をつけるclassを用意したいと思います。
list-item.component.css
// 以下を追加
:host.list-item.first {
  background-color: #7ae5ec;
}

:host.list-item.second {
  background-color: #7aecc0;
}

:host.list-item.third {
  background-color: #7ab9ec;
}
ここまでのビルド後イメージ

すべてのコンポーネントにclassが付与されて、背景色がつきました。


次は、2. 上記1に加えて、動的にclassの付け外しをするについてです。
list-item.component.css
export class ListItemComponent implements OnInit {
  @HostBinding('class')
  @Input() name: string; // ①
  
  // 今回formは用意していないので、例としてだけ挙げます
  @HostBinding('class.valid') get valid() {
    return this.form.valid;
  } // ②

  @HostBinding('class.list-item') isClick = false; // ③-A
  ...
  onClick(): void {
    this.isClick = !this.isClick;
  } // ③-B

他にもいろいろな方法があると思うのですが、簡単に思いつくものを挙げてみました。

①は、Input()で受け取った値を使用します。
組み合わせて使うだけで、特別なことをしてる感じがします...!

②について、今回Formは用意していないので記述の例になるのですが、状態など値そのものを監視したい時に使える方法です。

getterってあまり使う機会がなかったのですが、今回試してみたところ使い勝手がいいですね!


また③は、②のようにイベント発生時ではなく、識別子に設定した変数の値を書き換えることによってclassの付け外しをしています。

ここまでで、上記の①と③をプログラムに落とし込んだビルド後のイメージが以下のようになります。

それぞれで別々のclassの付与と、classの付け替えができました!

補足

ここまでclassを付与する使い方を紹介してきましたが、なんとHostBindingはclass以外のバインディングにも使えます。
例えば、「@HostBinding('style.display') flex = 'flex';」としてあげればstyle="display: flex;"がバインドされます。
便利!

今回は公式以外に以下サイトも参考にしたのですが、「HostBinding('value') myValue;は[value]="myValue"と全く同じです。」という一文が特にわかりやすかったです。
@HostBindingと@HostListener:彼らは何をし、何のためにいますか?


以上、HostBindingデコレータについて紹介しました。
参考になればうれしいです。