・新規サービス作成手順
    ソリューションフォルダ「Servers」を右クリックし、「追加」⇒「新しいプロジェクト」を選択する
    
    「Vusual C#」カテゴリの「Windows」の配下にある「Windows サービス」を選び、名前を指定してOKを押下

    プロジェクトのプロパティを開き、「アプリケーション」の「対象のフレームワーク」を「.NET Framework 4」
    に変更する

    最初にService1.csが作成されるので、デザイナで何もないところをクリックし、
    プロパティウィンドウから「インストーラの追加」を選ぶ

    生成されたProjectInstaller.csの"serviceProcessInstaller1"と"serviceInstaller1"から
    数字の"1"を消して"serviceProcessInstaller"と"serviceInstaller"に名前を変える

    serviceInstallerのプロパティに以下の文字列を指定する
        DisplayName:サービス一覧画面に表示する名前
        Description:サービス一覧画面に表示する説明。
        ServiceName:サービスの識別名。プロジェクト名を指定する
        StartType:インストール直後のスタートアップの種類
        Accout:サービスの実行アカウントの種類を選択する

    サービス登録(batで以下を実行)
        C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil C:\Service.exe
        pause

・バイナリ実装
    16進数変換
        Convert.ToByte(Convert.ToString(filever, 16), 16)

    BCD変換
        int i,j;
        string s = "1001000043004865617020616E6420737461636BA5";
        len = s.Length / 2;
        byte[] num16 = new byte[len];

        j = 0;
        for ( i = 0; i < len; i++ )
        {
          num16[i] = Convert.ToByte(s.Substring(j, 2), 16);
          j += 2;
        }

    バイナリ書き込み
        using(MemoryStream st = new MemoryStream())
        using(BinaryWriter bw = new BinaryWriter(st))
        {
        }

        using(FileStream fs = new FileStream(filePath, FileMode.Append))
        {
            st.CopyTo(fs);
        }

    Datatable
        文字列の重複削除
            dataTable.AsEnumerable().Select(row =>
            row.Field<string>("MOJIRETSU")).Distinct().Count();

        日付の重複削除
            dataTable.AsEnumerable().Select(row =>
            row.Field<DateTime>("HIZUKE").Date).Distinct().Count();

        日付の抽出
            dataTable.Select("HIZUKE >= #" + DateTime.Parse("2015/08/15" + "# AND HIZUKE < #" +
            "2015/08/15" + "#").Count()

    親子関係の考え方
        A(A.1(A.1.1),A.2(A.2.2)....)
        第二階層(A.1、A.2...)の数=Aの件数

    更新日付が最新のものを複数テーブルの更新日付から取得
    Oracle
        SELECT
            UPD_DATE
        FROM
        (
            SELECT
                UPD_DATE
            FROM
            (
                SELECT
                    MSMR.UPD_DATE
                FROM
                    TABLEA MSMR
                WHERE
                    MSMR.UPD_DATE = (SELECT MAX(UPD_DATE) FROM TABLEA)
                UNION ALL
                SELECT
                    MSMN.UPD_DATE
                FROM
                    TABLEB MSMN
                WHERE
                    MSMN.UPD_DATE = (SELECT MAX(UPD_DATE) FROM TABLEB)
            ) A
            ORDER BY UPD_DATE DESC
        )
        WHERE
            ROWNUM = 1;

    降順データ取得
    Oracle
        SELECT
            T.COLUMN1, T.COLUMN2
        FROM
        (
            SELECT
                TABLE1.COLUMN1, TABLE1.COLUMN2
            FROM
                TABLE1
            ORDER BY
                TABLE1.COLUMN2 DESC
        ) T
        WHERE
            ROWNUM <= 2;

    SQL SERVER
        カーソル
            一時テーブルに入れたデータを順次取得して、
            テーブルからのデータの取得処理に使う
        1.一時テーブル定義
        2.一時テーブルに条件を格納(INSERT)
        3.一時テーブルにカーソルセット
        4.一時テーブルから順次取得した値(条件)で、テーブルからデータを取得

        /* カーソル宣言 */
        Declare dataCursor Cursor For
        Select
            dataType
        From #dataView

        Open dataCursor

        Fetch Next From dataCursor
        Into @dataType

        While @@FETCH_STATUS = 0
        Begin
            Fetch Next From dataCursor
            Into @dataType
        End

・Excelで、アプリケーションを作成する際の注意点
    Excelを常時起動させたりすると、
    他のエクセルをOpen⇒Closeした際に同じインスタンスの他BookのExcelが
    全て閉じられてしまい、予期せぬ状態になりかねない
    ⇒お客さんに別プロセスで起動させる
        スタートメニュー⇒「プログラムとファイルの検索」の窓に、「regdit」と入力

        「HKEY_CLASSES_ROOT」⇒Excel.Sheet.12⇒Shellの上で右クリックして、
        「新規」にカーソルを乗せ、「キー」をクリック

        「別窓で開く」など、任意の名前を付ける

        「別窓で開く」を右クリックして、同じく「新規」にカーソルを乗せ「キー」をクリックする
        (ここでは必ず名前をcommandと入力する事)

        commandを選択した状態で、右側にある「既定」をダブルクリックする

        "EXEのフルパス" /x "%1" と入力する
        
        https://quartet-communications.com/info/topics/21941

・定期払い戻しの考え方
    定期払い戻し額=0
    SF残額 >= 手数料(手数料なしON)
    ※定期払い戻し能力なし、
     SFのみで払い戻した方が払戻額が大きい場合

    定期払い戻し額 = 0
    SF残額 >= 手数料
    ※定期払い戻し能力なし、
     SFのみで払い戻した方が払戻額が大きい場合

    定期払い戻し額 = 0
    SF残額 < 手数料
    ※定期払い戻し能力なし、
     SFのみで払い戻した方が払戻額が大きい場合

    定期払い戻し額 > 0
    定期払い戻し額+SF残額 <= 手数料
    ※SFのみで払い戻した方が払戻額が大きい場合

    定期払い戻し額 > 0
    定期払い戻し額+SF残額 > 手数料
    定期払い戻し額 <= 手数料
    ※SFのみで払い戻した方が払戻額が大きくなりうる場合

    定期払い戻し額 > 0
    定期払い戻し額+SF残額 > 手数料
    定期払い戻し額 > 手数料
    ※定期払い戻し含む払い戻しの方が大きくなる場合

・Visual Studioで使用しているtrnames.oraの場所
    sqlplus @?
    と実行して出てくるパスを指定

・テーブル作成 Oracle
    表領域(USER01)をファイル名「USER01.dbf」、100MBのサイズで作成する
    CREATE TABLESPACE IBKIC_DTI
        DATAFILE 'C:\IBKIC_DTI.dbf' SIZE 100M
        SEGMENT SPACE MANAGEMENT AUTO

・DB接続時に必要 Oracle
    <add key="DBConnectionTimeout" value="10" />
    <add key="DBCommandTimeout" value="10" />
    ⇒リトライ処理も

・交通系用語
    飛びつき
        定期外から定期区間内へ
    乗り越し
        定期内から定期外へ
    飛びつき乗り越し
        定期外⇒定期内⇒定期外

    電子スターフ
        車内のディスプレイ

・再現確認反省
    再現確認方法見直し
        まずは手順通りに再現確認
        そうでなければ、どのような条件なら再現するか無理やりDEBUGオードで場所を変えてもいいので再現確認する

    ※仮に修正済みで再現しない場合でも、
     再現しうる条件を順番に提起し、
     最終的にAがBに変更になったため、再現はできない旨報告する

・GYAOとABEMAの違い
    GYAO:CMなし、コンテンツ見放題
    ABEMA:CM、プレミアム(過去視聴分)

・気づかなかった
    integer⇒long

    なるべく現地の環境に合わせて試験をする
    ⇒タスクスケジューラで起動される、等

    数値のカンマ区切り

    左寄せ、中央寄せ、右寄せ

    帳票の確認方法
    ⇒何が出るのか正しくて何が出ないのが正しいのかを確認する
     画面と帳票の比較
     帳票同士の比較

・一部文字列抽出
    =MID(D1,LEN("hogehoge")

・キャッシュクリア SQLSERVER
    DBCC DROPCLEANBUFERS
    DBCC FREEPROCCASHE

・気づかなかった
    期限切れログデータ削除
    非同期
    列挙型の値変更
    タイムアウト
    リトライ
    DB,WEBAPIからデータ取得時 outofmemory
    非同期の必要性 還元データ
    テスト 罫線の確認
    テスト 日付確認 今日以外にしてもちゃんと今日以外の日付が出るか
    テスト 計算式
    テスト ~しながら...を変えたときに正しく変わること
    計登板後_系統番号が違う場合、系統名称のみ違う場合
    カレンダー画面と計上日を変更して作成ボタンを押下した場合の挙動
    ⇒背景色が白なので、予約可能として処理されてしまう
    カレンダーは常時最新でない為、取得しに行ってエラーだった場合に
    どうするか⇒一件でもエラーならエラーとするか、Oracleでtnsnames.ora
    で接続できない
    ⇒datasource内を直接指定
    帳票:出すものがないなら0件エラーを出す
    スクリプトをお客さんに出す時に注意
        Use [テーブル名]
        go
        を必ず入れる

・C# Tips
    DBからのデータ読み出し高速化
    AsNoTracking()
    IEnumerable<IEnumerable<Town>> towns = dbContext.Towns.AsNoTracking().OrderBy(t => t.TownID).Batch(200000);

    ストアド作成時の注意事項
        結合したデータがNULLだった場合に、何を出すか確かめておく
        ⇒数値の場合はゼロ
        ⇒文字列の場合は~コード等
         例)路線名がNULLなら路線番号

・数値変換
    16進数を10進数に変換
        0x15
        1*16+5
        ⇒10進数 21

    10進数を16進数に変換
        21*16=1...5
        ⇒16深栖 15

    BCD
        0x15
        ⇒10進数 15

・Winmergeで抜け漏れが発生しないようにする
    フォント:HGゴシックM
    差異色:青

・IDENTITY属性を指定している場合のINSERT
    // IDENTITY属性を指定している列名保持用
    string indexColumnName = "";
    MetadataProperty storeGeneratedPatternProperty = null;
    foreach(var item in entry.EntitySet.ElementType.Members)
    {
        storeGeneratedPatternProperty = item.MetadataProperties.Where(f =>
        f.Name.Contains("StoreGeneratedPattern")).FirstOfDefault();
        if(storeGeneratedPatternProperty != null &&
        Convert.ToString(storeGeneratedPatternProperty.Value) == "Identity")
        {
            indexColumnName = item.Name;
            // IDENITY属性を指定された列に値を格納しても正常に動作するようにSQL文を変更
            sql = string.Format("SET IDENTITY_INSERT {0} ON ", tableName) + sql;
            break;
        }
    }

・実行するメソッドXMLで管理する
    <?xml version="1.0" encoding="utf-8"?>
    <TaskPool>
        <TaskSet TaskSeID="0001" TaskSetName="処理開始" UseFormIDs="Form1"
        StartTaskItemID="0001" CommonTask="false" ReportTaskNumber="1" NameSpace="Task"
        CardType="" PatternNames="">
            <OperationJudgePool>
                <OperationJudge MethodID="JudgeMethod1" ErrorMessage="Err_0001"
                SuggestionMessage="Sug_0001" MethodComment="判定" />
            </OperationJudgePool>
            <TaskCheckPool>
                <TaskCheck MethodID="CheckMethod1" MethodArg="" MethodComment="エラーリカバリ" />
            </TaskCheckPool>
            <TaskItem TaskItemID="0001" TaskItemName="読み込み開始" UseFormID="Form1">
                <Preload>
                    <Action MethodID="Method1" MethodArg="0001" MehodComment="メソッド(0001)" />
                </Preload>
                <Loaded />
                <StatusUpdate />
                <DecideMethod />
                <Buton1Pushed>
                    <Action MethodID="Transfer" MethodArg="0007" MethodComment="処理終了" />
                </Buton1Pushed>
                <Button2Pushed />
                <Leaved />
            </TaskItem>
            <TaskItem TaskItemID="0007" TaskItemName="処理終了" UseFormID="Form2">
                <Preload>
                    <Action MethodID="Method2" MethodArg="" MehodComment="機能終了" />
                </Preload>
                <Loaded>
                    <Action MethodID="Method3" MethodArg="Form1" MehodComment="前画面終了" />
                <Loaded />
                <StatusUpdate />
                <DecideMethod />
                <Buton1Pushed />
                <Button2Pushed />
                <Leaved />
            </TaskItem>
        </TaskSet>
    </TaskPool>

・Task管理用XML
    埋め込まれたリソースに設定し、
    名前空間を省略せずに記載するとXMLを取得できる

・DBのログを削除する方法
    データベース⇒タスク⇒圧縮⇒ファイル
    ファイルの種類:ログ
    未使用領域を解放する

・Visual Studioのビルドイベント
    既にコピー先に存在する場合は失敗するので注意。 /yで上書き確認しないようにしておく必要がある
    copy "$(ProjectDir)log.config" "$(OutDir)log.config" /y

・変換処理
 16進数文字列からbyte配列を生成
    if(string.IsNullOrEmpty(str))
    {
        return null;
    }
    int len = str.Length / 2;
    byte[] bytes = new byte[len];

    for(int i = 0, j = 0; j < len; i++, j += 2)
    {
        bytes[i] = Convert.ToByte(str.Substring(j, 2), 16);
    }
    return (byte[]).bytes.Clone();

・変換処理
 byte配列から16進数文字列を生成
    if(null == bytes)
    {
        return string.Empty;
    }
    StringBuilder sb = new StringBuilder(bytes.Length * 2);
    foreach(byte b in bytes)
    {
        sb.Append(string.Format("{0:X2}", Convert.ToInt32(b));
    }
    return sb.ToString();

・Entity Framework
 ストアドプロシージャの戻り値を型で取得する方法
    edmxのデータベース更新でストアドを取得した後、
    モデルブラウザー~、store-ストアドプロシージャ―関数インポート
    列情報の取得+複合型の作成

・C# ストアド ジェネリックス
    objectParameter[] para;
    ObjectResult<T> result = this.m_objectContext.ExecuteFunction<T>(ストアド名, para);

・list.sortの書き方
    result.Sort((x, y) => x.USAGE_DATE.CompareTo(y.USAGE_DATETIME));

・現在格納されているデ―タのINSERT文生成方法
    データベースを右クリックし、メニューから[タスク]⇒[スクリプトの生成(E)。。。]
    データベース全体または特定テーブルのいずれかを選択して次へ
    詳細選択をクリックして、スクリプトを作成するデータの種類を[データのみ]に変更する
    確認画面で次へを押すと出力開始

・Excelのキャプチャ(ヘッダ、フッタあり)
    PDFで保存⇒Snipping ToolExcel 保存時 通貨 カッコ つけさせない
    ExBook.SaveAs(i_saveFileName, Local:true);

・Excel 勤務時間を三等分したい場合
    シリアル値を分単位に直す
    分単位にした値/3を再びシリアル値に戻す
    ※
    ・シリアル値を分単位にする方法⇒シリアル値*(24 * 60)
    ・分単位をシリアル値に戻す⇒シリアル値/(24*60)
    ・分単位にした値を/3の値を求める⇒QUOTIENT(4G8*24*60, 3)
    ・割り切れる値かどうか判定する方法⇒/3した結果が1かどうかで判定
     ⇒ROUND(MOD($G8*24*60, 3), 0)

・sqlserverストアド インデックスを張る方法
    ・実行して結果まで出るクエリ部を全選択
    ・ツールバーの推定実行プランの表示を選択
    ・GUI画面の中で、「不足しているインデックス」を右クリック、詳細を表示する
    ・インデックスのコマンドが取得できるので実行する