星期六, 9月 30, 2023

[SSMS] 產生變更指令碼

對於不熟悉 ddl 語法的人來說,要使用 ddl 語法來新增或變更 table 會花上不少時間尋找語法資料,在 SSMS 上有提供功能,可以取得變更的 ddl Script 語法,可以直接拿來應用或快速取的關鍵字

在 AdventureWorks2022 Person.Person Table 上新增 NewColumn 


新增 NewColumn 後,先不要進行儲存,會有下圖 - [產生變更指令碼] 功能出現


點選後就會出現這段 Script 可以複製出來使用
/* 為了避免任何可能發生資料遺失的問題,您應該先詳細檢視此指令碼,然後才能在資料庫設計工具環境以外的位置執行。*/
BEGIN TRANSACTION
SET QUOTED_IDENTIFIER ON
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
SET CONCAT_NULL_YIELDS_NULL ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
COMMIT
BEGIN TRANSACTION
GO
ALTER TABLE Person.Person ADD
	NewColumn nchar(10) NULL
GO
ALTER TABLE Person.Person SET (LOCK_ESCALATION = TABLE)
GO
COMMIT

星期一, 9月 18, 2023

[C#] InitializeComponent()

以往看見 InitializeComponent() 在 Form.cs 內而不是在 designer.cs 的 Code,都是些較早期的網路範例 Code,這次在公司內部發現 WinForm Project 發現,紀錄該情況

標準 Form

標準 Form 應該會附帶一個 designer.cs 檔案,建構子內會有 InitializeComponent(),是指向 designer.cs 檔案


designer.cs 檔案內會有 Form 控件相關設定值
namespace WindowsFormsApp1
{
    partial class Form1
    {
        /// <summary>
        /// 設計工具所需的變數。
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// 清除任何使用中的資源。
        /// </summary>
        /// <param name="disposing">如果應該處置受控資源則為 true,否則為 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form 設計工具產生的程式碼

        /// <summary>
        /// 此為設計工具支援所需的方法 - 請勿使用程式碼編輯器修改
        /// 這個方法的內容。
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(800, 450);
            this.Text = "Form1";
        }

        #endregion
    }
}
非標準的 Form

如下圖,Form 內沒有 designer.cs 檔案,InitializeComponent() 則是都在 Form.cs 檔案內,說實話也不知道要如何稱呼該 Form


重現該 Form

反覆建立 Form 後發現,只要新增一個類別檔案,再去繼承 System.Windows.Forms.Form 後,等同於把 class 轉成 Form 後就會出現該情況,但該情況也可以正常運行,公司內的 Code 已經存在很久,還是 FormBase 設計,每個 Form  都要去繼承它,沒有因為該情況而產生異常過

不肯定是否還有其他方式也會發生,只試出該情況,VS 環境為 VS2022

星期一, 9月 11, 2023

[SQL] 查詢 SQL Server 版本

根據官方文章 - 判斷 SQL Server Database Engine 所執行的版本和版次 並整合舊文章,重新整理該筆記

SSMS 連線資訊


錯誤記錄檔案 (ErrorLog)


@@version
SELECT @@VERSION
Microsoft SQL Server 2022 (RTM) - 16.0.1000.6 (X64)   
Oct  8 2022 05:58:25   
Copyright (C) 2022 Microsoft Corporation  Developer Edition (64-bit) 
on Windows 10 Pro 10.0 <X64> (Build 19045: ) (Hypervisor) 
SERVERPROPERTY 和相關語法
SELECT
  @@SERVERNAME AS [SERVER_NAME] ,
  @@SERVICENAME AS [SERVICE_NAME] ,
  RIGHT(LEFT(@@VERSION,25),4) AS 'SQL Server' ,
  SERVERPROPERTY('ProductVersion') AS ProductVersion,
  SERVERPROPERTY('ProductLevel') AS ProductLevel,
  SERVERPROPERTY('Edition') AS Edition
SERVERPROPERTY() 的 ProductLevel 屬性回傳值
  1. RTM = 原始發行版本
  2. SPn = Service Pack 版本
  3. CTP = Community Technology Preview 版本
SQL Server 2017 開始就沒有 SP,只有 Cumulative Update (CU) 而已,詳見 No More Service Packs for SQL Server

已安裝的 SQL Server 功能探索報告 





星期五, 9月 08, 2023

[C#] FlowLayoutPanel 閃爍

Line 社群問題
在 WinForm FlowLayoutPanel 內要增加 100 個 Panel,造成畫面卡頓
第一時間是先測試 DoubleBuffer、SuspendLayout、ResumeLayout 這設定組合,發現完全沒有改善,接續才是朝向 FlowLayoutPanel 是否有特殊設定方向找,發現該討論 During FlowLayoutPanel scrolling, background distorts + flickers 可以改善該情況,以下測試 Code 是把 Label 塞進自訂 FlowLayoutPanel 內並觀察效果

UCFlowLayoutPanel - 覆寫 CreateParams

WS_CLIPCHILDREN 參數官方說明
Excludes the area occupied by child windows when drawing occurs within the parent window. This style is used when creating the parent window.
這說明和網路上討論文章相符,都在在探討控件重疊時要如何繪製控件,後來發現把 Label 放進 FlowLayout 內也是一種控件重疊,另外該參數通常都會連 WS_CLIPSIBLINGS 一起研究討論
using System.Windows.Forms;

namespace FormFlickr
{
    public class UCFlowLayoutPanel : FlowLayoutPanel
    {
        public UCFlowLayoutPanel()
        {
        }

        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams cp = base.CreateParams;
                cp.ExStyle |= 0x02000000; // WS_CLIPCHILDREN
                return cp;
            }
        }
    }
}

在 UCFlowLayout 內塞進 500 個 Label 控件


using System;
using System.Windows.Forms;

namespace FlowLayoutPanelFlickr
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            for (int i = 0; i <= 500; i++)
            {
                Label label = new Label();
                label.Name = i.ToString();
                label.Text = i.ToString("000");

                // 設定這兩個屬性單純讓測試效果更明顯
                label.AutoSize = true;
                label.BorderStyle = BorderStyle.Fixed3D;
                flowLayoutPanel1.Controls.Add(label);
            }
        }
    }
}

測試結果

改善前


改善後


雖然覺得對於 WS_CLIPCHILDREN 應用還一知半解,但改善效果有出來就先紀錄下來

星期一, 9月 04, 2023

[VS] 偵錯 - 例外狀況設定

例外狀況設定為偵錯時遇上 Exception 要不要停止的設定,該視窗在 VS => 偵錯 => 視窗 => 例外狀況設定


在 告知偵錯工具在擲回例外狀況時中斷 文章內以 AccessViolationException 為例說明,C# Code 如下
namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            try
            {
                throw new AccessViolationException();
                Console.WriteLine("here");
            }
            catch (Exception e)
            {
                Console.WriteLine("caught exception");
            }
            Console.WriteLine("goodbye");
            Console.ReadLine();
        }
    }
}
在例外狀況設定內搜尋並勾選 AccessViolationException


執行偵錯時即使該 Exception 包在 try catch 內,還是會停在下圖第 17 行 throw new AccessViolationException() 上


另外上圖 [於擲回這個例外狀況類型時中斷] 可以直接取消該 Exception,沒有勾選該 Exception 情況下會直接輸入,如下圖


最後例外狀況設定有提供 [將清單還原為預設設定] 選項


星期日, 9月 03, 2023

[SQL] 備份加密 - 還原

上篇筆記紀錄 [SQL] 備份加密 - 備份,該篇根據官方文章 - 備份加密 內還原步驟,來把加密過備份檔案還原至新 instance 上,還原步驟依序為
  1. 在原 instance 上備份憑證
  2. 在新 instance 上的 master DB 上建立 master key
  3. 在新 instance 上匯入憑證
  4. 在新 instance 上還原 DB
加密過備份檔案還原完整 Script
-- Step1:在原 instance 上備份憑證
BACKUP CERTIFICATE AdventureWorksCert 
TO FILE = 'C:\Temp\AdventureWorksCert'
WITH PRIVATE KEY 
	(
		FILE = 'C:\Temp\AdventureWorksKey',
		ENCRYPTION BY PASSWORD = 'P@ssW0rd' -- 指定憑證私鑰檔案的密碼
	)
    
-- Step2: 在新 instance 上的 master DB 上建立 master key   
USE master;
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'P@ssw0rd_In_New_Instance';    
    
-- Step3:在新 instance 上匯入憑證
CREATE CERTIFICATE AdventureWorksCert
FROM FILE = 'C:\Temp\AdventureWorksCert'
WITH PRIVATE KEY 
	(
		FILE = 'C:\Temp\AdventureWorksKey',
		DECRYPTION BY PASSWORD = 'P@ssW0rd' -- 使用憑證私鑰檔案的密碼
	) ;
    
-- Step4:在新 instance 上還原 DB
RESTORE DATABASE AdventureWorks2022
FROM DISK = 'C:\Temp\AdventureWorks2022.bak'
WITH REPLACE
    
Step1:在原 instance 上備份憑證

BACKUP CERTIFICATE 除了 ENCRYPTION BY PASSWORD 還有 DECRYPTION BY PASSWORD 參數,該憑證建立時是用 master key 的話,備份憑證時就不用指定該參數

此外備份時該憑證 private key 已經存在,不會直接覆蓋,會有下列錯誤訊息
無法寫入檔案 'C:\Temp\AdventureWorksKey'。請確認您具有寫入權限、檔案路徑有效且該檔案尚未存在。

Step2:在新 instance 上的 master DB 上建立 master key

在新 instance 建立 master key 的密碼,不用一定要跟舊 instance 一樣,已經存在 master key 的話可以省略該步驟

Step3:在新 instance 上匯入憑證

[匯入憑證時指定 DECRYPTION BY PASSWORD 的密碼] 一定要跟 [備份憑證時指定 ENCRYPTION BY PASSWORD 的密碼] 一樣,不一樣會出現下列錯誤訊息
私密金鑰密碼無效。
另外進行匯入憑證前,一定要建立 master key,雖然沒有用上它,要不然會有該錯誤訊息產生
執行此作業之前,請在資料庫中建立主要金鑰或在工作階段中開啟主要金鑰。

Step4:在新 instance 上還原 DB

沒有憑證情況下進行還原,會出現列錯誤訊息
找不到指模為 '0xAD763446520338DC5EC78D027B1201362048AEB6' 的伺服器 憑證。RESTORE DATABASE 正在異常結束。
最後在 備份加密-限制 說明內,有提到兩點還原注意事項
  • SQL Server Express 和 SQL Server Web 不支援備份期間加密。 但是可支援從加密的備份還原到 SQL Server Express 或 SQL Server Web 的執行個體。
  • 舊版 SQL Server 無法讀取加密的備份。

星期六, 9月 02, 2023

[SQL] 備份加密 - 備份

SQL Server 2014 功能,僅針對備份檔案進行加密,確保離線資料安全,該篇根據官方文章 - 建立加密的備份 的操作筆記

備份檔案加密完整 Script
-- Step1:在 master database 上建立 master key
USE master;
GO
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'P@ssw0rd';
GO

-- Step2:建立憑證
CREATE CERTIFICATE AdventureWorksCert
    WITH SUBJECT = 'AdventureWorks Database Backup Certificate';
GO

-- Step3:進行備份檔案加密
BACKUP DATABASE AdventureWorks2022
TO DISK = 'C:\Temp\AdventureWorks2022.bak'
WITH
    INIT ,
    FORMAT ,
    COMPRESSION ,
    ENCRYPTION 
	(
		ALGORITHM = AES_256, 
		SERVER CERTIFICATE = AdventureWorksCert
	) ,
    STATS = 10 

Step1:在 master database 上建立 master key

master key 是一個用來保護憑證私密金鑰和資料庫中非對稱金鑰的對稱金鑰。 建立 master key 時,系統會利用 AES_256 演算法和使用者提供的密碼來加密主要金鑰
Step2:建立憑證

使用 CREATE CERTIFICATE 語法建立憑證,有兩個重點參數要注意

*ENCRYPTION BY PASSWORD


指定用來加密私密金鑰的密碼,不指定情況下會用 master key 來當成預設密碼

假如自行指定 ENCRYPTION BY PASSWORD,而非使用 master key,使用該憑證進行備份檔案加密時,會有下述錯誤訊息

無法使用 憑證 'CustomPasswordCert',因為其私密金鑰不存在,或未受到資料庫主要金鑰保護。SQL Server 必須能夠自動存取這項作業所用之 憑證 的私密金鑰。BACKUP DATABASE 正在異常結束。

 

*EXPIRY_DATE


憑證到期日期,為 UTC 時間,若未明確指定,預設為 START_DATE 加一年的日期

使用憑證進行加密的備份也會檢查到期日,而且將不會允許使用已過期憑證來建立新備份,但將會允許使用已過期的憑證來還原。
-- 確認 UTC 時間
SELECT GETUTCDATE()

-- 建立不久後就過期憑證
CREATE CERTIFICATE AdventureWorksCert_EXPIRY_DATE
WITH 
      SUBJECT = 'AdventureWorks Database Backup Certificate' ,
      EXPIRY_DATE = '2023-09-02 03:00:00.000';
GO
進行備份時就會出現下述錯誤訊息
為備份加密所指定的憑證已過期。BACKUP DATABASE 正在異常結束。

Step3:進行備份檔案加密

BACKUP DATABASE 搭配 ENCRYPTION 參數來進行備份加密,進行備份加密時,假如還沒有備份憑證,會有下列提醒文字
警告: 用來加密資料庫加密金鑰的憑證尚未備份。您應該立即備份此憑證和與此憑證關聯的私密金鑰。萬一憑證無法使用時,或者您必須還原資料庫或將它附加到另一部伺服器時,就必須有憑證和私密金鑰的備份,否則就無法開啟資料庫。

備份檔案加密不支援附加至現有備份組,下述備份語法故意移除 Format 參數,進行備份時就會出現錯誤訊息
-- 移除 Fomrat 參數
BACKUP DATABASE AdventureWorks2022
TO DISK = 'C:\Temp\AdventureWorks2022.bak'
WITH
    INIT ,
    -- FORMAT ,
    COMPRESSION ,
    ENCRYPTION
	(
		ALGORITHM = AES_256 ,
		SERVER CERTIFICATE = AdventureWorksCert
	) ,
    STATS = 10
無法執行備份,因為要求的是 'ENCRYPTION',但媒體之前是以不相容的結構格式化。若要附加此媒體集,請省略 'ENCRYPTION',或在您的 BACKUP 陳述式中使用 WITH FORMAT 來建立新媒體集。如果在現有媒體集上使用 WITH FORMAT,將覆寫其所有備份組。