顯示具有 程式筆記 標籤的文章。 顯示所有文章
顯示具有 程式筆記 標籤的文章。 顯示所有文章

2021/03/24

20210324-技術-Oracle-Online新增及調整Table (Sub)Partition欄位+填入資料作法


需求邏輯


(用概念記錄一下這次的開發邏輯,順便做的思緒的統整)

這一次的處理,可達到以下需求:

  • TableA新增一個欄位 ColumnB。
  • 依照TableY的資料,填入ColumnB。
  • 將原本TableA的Subpartition的欄位依據,從ColumnA 改為 ColumnB。
  • 一切要 線上調整,不可以downtime.


參考文


最終採用 DBMS_REDEFINITION 實作:

  1.  Performing a large correlated update – Learning is not a spectator sport
    • 這篇直接達到我的需求,使用REDEFINITION調整Schema外,還同時可以「填資料」!
  2. dbms_redefinition example
    • 一篇標準的 DBMS_REDEFINITION 的使用方式,說明各步驟的用意。
  3. DBMS_REDEFINITION (官網)
    • 各函式的參數說明


更新大量資料(update data)的作法 參考文:

  1. Efficient way to UPDATE bulk of records in Oracle Database - Oracle Database
    • 做了各類Update的效能比較(裡面有6類的寫法,採「直接update」效率最差 )。
  2. Oracle update tuning tips
    • 各類的update說明
  3. Update very large Oracle table tips
    • 使用CTAS (Create Table As Select) 的速度最快
    • (此篇沒有細部講做法)


前言

(隨性寫寫這次的背景故事吧)

當初在 加欄位後補上資料 的這個需求時,用基本的update處理,但PRD 上有 上億筆 的資料,讓我必需重新考慮 Table Lock 及效能的議題。

而原本調整 Table Subpartition Column的實作方式,是採用 DBMS_REDEFINITION 這 Utility處理。

(DBMS_REDEFINITION 最大優勢:Online Handle !!!)

所以開始思考,它能不能 在調整Schema 時,又 同時 做掉填資料呢? 最後 找到了 “參考文” 所述的作法。


另外, 最快的作法 是 CTAS :於另Table整理好資料後,再 做exchange.


實作時的各個”雷區”


授權

(https://t.ly/R4xi)

GRANT ALL ON SYS.DBMS_REDEFINITION TO TEST;
GRANT CREATE ANY TABLE, ALTER ANY TABLE, DROP ANY TABLE, LOCK ANY TABLE, SELECT ANY TABLE TO TEST;


事前準備

  1. 建立_INT的表格  (Interim)
    • 從CTAS方式建立,包括 調整為正確的subpartition column.
  2. 要手動補上其Subpartition資訊,不然在Redefinition時會死掉 !
    • 我是自寫一個loop,依據 TableA 去建立 TableA_INT 的Subparitition.
    • 從這Table取得資訊:USER_TAB_SUBPARTITIONS
  3. 建立好的TableA_INT Table,要將它其下的Constraint 移除 (這是從CTAS方式建立時產生)
    • 這是在執行「COPY_TABLE_DEPENDENTS」時會發生的錯誤。
    • 自寫一個Loop,從這Table:USER_constraints 取得其相關資訊,再將它移掉
    • 語法:ALTER TABLE  XXX DROP CONSTRAINT YYY;

建立Function

    這是為了讓DBMS_REDEFINITION的定義,可以”填資料”

    •     最重要的是 Function要加上 "DETERMINISTIC" 才可以被運作

   CREATE OR REPLACE FUNCTION GetXXXX( ….) RETURN DATE DETERMINISTIC AS ~~ BEGIN ~~END;


處理的Key依據

        官網(各函式說明):https://t.ly/VnV9

        DBMS_REDEFINITION.CONS_USE_PK
         DBMS_REDEFINITION.CONS_USE_ROWID

    • 這要留意的是使用「ROWID」,則在 執行 DBMS_REDEFINITION 後,它會產出「unused」的欄位!這要手動移除
    • 語法:ALTER TABLE XXX DROP UNUSED COLUMNS;


CAN_REDEF_TABLE

  • 檢查Table是否可以執行DBMS_REDEFINITION ?


START_REDEF_TABLE

  • 在這一步,就已將資料copy 至 TableA_INT的表格了
  • 額外取得資料填入,於此步驟定義。
  • 未執行完成,則要用 ABORT_REDEF_TABLE 釋放。不然會刪除不掉_INT的表格。


COPY_TABLE_DEPENDENTS

  • 此Table原本的約束(Index/FK/PK……),靠此函式同步保留住的
  • 出現這種錯誤:ORA-00904: "XXXColumn": invalid identifier,(我是無解), 將它的Ignore Error 屬性設為true.


SYNC_INTERIM_TABLE

  • 這設定,是當處理 DBMS_REDEFINITION 時,若有 其它的Session 異動 TableA時,它會自動同步到 TableA_INT


FINISH_REDEF_TABLE

  • 這一步,才會真正將 TableA 與TableA_INT 做交換。
  • 結束整個 DBMS_REDEFINITION 流程


刪除INT 表格及Unused 欄位

  • INT 表格也是實際占空間的,要刪除;語法:DROP TABLE xxxx CASCADE CONSTRAINTS PURGE;
  • Unused欄位 要記得刪除。



結論

       

使用 DBMS_REDEFINITION,目的就是 這些 Online 異動 全交給它,

這次是頭一次使用這Utility。到時再記錄跑「上億」筆的異動要多久了,

然後,這一次自寫客製的Scripts,很多,將它分成「準備」「執行」那步驟,並寫個「Revert」的流程,以便於重新再次執行 (便於反覆測試)


後續更新

1.

處理的資料量大時,不要使用「CONS_USE_ROWID」,會產生大量的LOG(??)

使用「CONS_USE_PK」讓其對應,不用再產生ROWID欄位了。

2.

照理是可以Online 操作,而最後一步「FINISH_REDEF_TABLE」 則是真正的切換動作。

若怕它造成「Package Invalid 」等意外狀況,可以獨自於「離峰」時期執行。


(THE END)

2021/01/20

20210119-程式-Oracle Linux 7.8 安裝Docker 過程記錄

前言

這件事,本應是簡單到不行的,但又讓我踩了不少雷,來記錄一下,這安裝流程是什麼了。

踩到的雷: linux 下的yum repository ,當多份存在時,它會認不得該選那一個下載….


參考文

Install Docker on Oracle Linux 7 | Oracle Virtualization Blog
https://blogs.oracle.com/virtualization/install-docker-on-oracle-linux-7-v2


背景

新申請一台機器,而記得要開啟:防火牆:開80 443 8080   ,這是供yum install 時使用的

開始查看文章,執行相關的安裝指令

而 作業系統為:Oracle Linux 7.8   (不同的OS,會有不同的安裝方式)


開始作業


檢查yum repository的狀況

/etc/yum.repos.d/     #依此目錄下的所有Repo取得其資訊

cd /etc/yum.repos.d/    

查看目前目錄下的檔案

ls

因為我其下有不少的.repo,而導至我做 yum install 時會有錯誤

先備份沒有用到的Repo,然後刪除它 (會被影響)

zip origalrepo.zip oracle-linux-ol7.repo uek-ol7.repo virt-ol7.repo

取得公開的yum repository

wget http://yum.oracle.com/public-yum-ol7.repo         #使用public-yum-ol7.repo

# 文章說安裝Docker要將下述的Enable

vi public-yum-ol7.repo

(將這三類Enable)

  • ol7_latest, 
  • ol7_uekr4
  • ol7_addons

# 開始安裝

yum install docker-engine


#安裝完後 啟動

systemctl start docker
systemctl enable docker
systemctl status docker

#測試docker

docker run hello-world
docker ps -a

(完成)


結論

就是 被 Repo 的資訊有重覆所影響,導至我沒有「很順利」的安裝這簡單的事情。

在記做記錄一下了。


(THE END)

2020/11/09

20201109-技術-Oracle使用DBMS_DATAPUMP API執行匯入時遇到的問題


(純生活技術日記,沒有什麼機密可言的XDD)

這篇的焦點,就集中於「DBMS_DATAPUMP」這件事!


緣起


在做兩個Oracle DB之間的每月備份這需求,借助於 DBMS_DATAPUMP 的API工具,且達到 檔案不落地的方式,備份到目標的Archive Server.

在DEV環境建置時,遇到「ORA-31626: job does not exist」的問題,卡關卡好久!

在QAT環境建置時,以為會很ok,結果遇到「ORA-31631: privileges are required」的問題,讓我整整三天的時間,翻遍所有文章、問了能問的人,還是無解! 因為DEV OK,而到了QAT 不行,所以比對了兩個環境的:User權限、授權角色….該有的都有,但還是不對。



解決方式:

The gains and pains of dbms_datapump. Part II | Dani's IT Blog
https://danirey.wordpress.com/2009/09/15/the-gains-and-pains-of-dbms_datapump-part-ii/

(這一篇解教了我,完整的寫出 Source 及Target User 所需要的授權)

--Source 授權
--privileges for dbms_datapump
GRANT EXP_FULL_DATABASE TO XXXSOURCEUSER;
GRANT FLASHBACK ANY TABLE TO XXXSOURCEUSER;
GRANT CREATE SESSION TO XXXSOURCEUSER;     
ALTER USER XXXSOURCEUSER DEFAULT ROLE ALL;   --最後是這個解決此問題 !!!ORA-31631: privileges are required
        (註1:不一定要寫’ALL’,而是讓其EXP_FULL_DATABASE 角色 DEFULT_ROLE的flag變為YES )

       (註2:select * from session_roles;  知道每次此User登錄Session時,會預設授與的角色)
GRANT SELECT ON sys.v_$instance TO XXXSOURCEUSER;
GRANT EXECUTE ON sys.dbms_flashback TO XXXSOURCEUSER;


--Target上的授權
--privileges for dbms_datapump
GRANT IMP_FULL_DATABASE TO XXXTARGETUSERARCH;
GRANT DROP USER TO XXXTARGETUSERARCH;
GRANT ALTER USER TO XXXTARGETUSERARCH;
GRANT CREATE SESSION TO XXXTARGETUSERARCH;
GRANT CREATE TABLE TO XXXTARGETUSERARCH;
--GRANT FLASHBACK ANY TABLE TO target_user;
 
ALTER USER XXXTARGETUSERARCH DEFAULT ROLE ALL;
ALTER USER XXXTARGETUSERARCH QUOTA UNLIMITED ON users;
 
GRANT SELECT ON sys.dba_users TO XXXTARGETUSERARCH;
GRANT EXECUTE ON sys.dbms_flashback TO XXXTARGETUSERARCH;


針對Default Role Flag屬性 理解:

SELECT * FROM USER_ROLE_PRIVS; -- 此User的權限 (留意DEFAULT_ROLE欄位)

SELECT * FROM SESSION_ROLES ; --此USER登錄後的Session下的授與角色。

-----------------------------------------

此User在登錄後,代表了一個SESSION,而此Session的角色資訊,不一定”等同”於User的角色資訊。

視「DEFAULT_ROLE」的欄位=YES 而定。

若 角色的 DEFAULT_ROLE = YES,則Create Session時,就預設給予該角色。


ALTER USER XXXXXX DEFAULT ROLE ALL;   --將此USER下的角色,全設為DEFAULT_ROLE = YES.

ALTER USER XXXXXX DEFAULT ROLE CONNECT; --只有CONNECT為DEFAULT_ROLE,

-----------------------------------------

所以沒留意到「DEFAULT ROLE」這flag時,會發生 明明有將這角色給予此USER,但為何操作時還是說「沒有授權」呢?


結論:

有時,自已的筆記還是要寫完整的前因後果,將所要執行的授權清單整理出來  (且要分出 Source / Target 要執行的授權)

這一次過程中,我將看過的文章下,它所提到的授權,全部LOG下來,一個一個的實驗 (結果全不行)

但至少,我知道了我執行過那一些權限。

只要過了一段時間,沒有「被整理」的筆記,會讓自已完全想不出當時的情境是什麼。


(THE END)

2020/09/01

20200901-技術-建立Oracle 12C後的問題速記-建User/建DB Link

背景

在建立好Oracle 12CR2 in Docker 後,開始要摸索其使用方式,讓我要做的 Archive DB 功能可以運作。

而這幾乎每走一步,就會遇到些問題,然後寫下對應對筆記下來。

這邊,就速記下,這一天之中,所碰到的議題。


重點項目:

  1. 在建立USER / Schema時,才了解 Oracle 12C開始的架構:CDB / PDB (container概念)
    1. 遇到問題:ORA-65096: invalid common user or role name
  2. 建立Database Link:建立Public – 由sys建立後,各User使用。
    1. 遇到問題:ORA-01031: insufficient privileges
    2. 遇到問題:ORA-01017: invalid username/password; logon denied


技術開始


Oracle 12C的架構概念:CDB & PDB

( https://is.gd/LIcaDM – 架構說明&ORA-65096問題原因  )

  1. 查詢目前所在的PDB:select sys_context('USERENV', 'CON_NAME') from dual;
  2. 切換至目標的PDB: alter session set container=ARCH_PDB;
  3. 「CDB$ROOT」可以想像為之前Oracle 下的sys相關的table 資訊。
  4. 在「CDB$ROOT」下是無法建立USER的,會得到此ORA-65096: invalid common user or role name。
  5. 切換後就可以正常建立USER。



建立USER後它無法連線 – 要給予相關授權

(https://t.ly/yMvwy - 相關角色&授權 |  )

  1. 要讓SQL Develop Tool 可以連線,要「GRANT CONNECT to XXXUSER;
  2. 其它的就參考文章去授權。

而其中,SQL Develop Tool 的連線,若要用該User連線至其PDB的話,要選擇「Service Name 」(用sys連線時是用SID)

不然會一直出現 帳/密 錯誤。



建立Database Link - 遇到 USER 帳/密錯誤的問題

建立Database Link 的語法: (使用Using connection string )

CREATE PUBLIC DATABASE LINK "DBLINK_LIVE"
    CONNECT TO "targetUser" IDENTIFIED BY "XXX(密碼)XXX"
    USING '(DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = 22.22.22.22)(PORT = 1521))) (CONNECT_DATA = (SID = XXXX)(SERVER = DEDICATED)))';

2020/08/18

20200818-技術-在Docker升級Disk後的Issue處理-Docker / Oracle

在MIS加完Linux Disk 的空間後,所遇到的一連串事情,來做個記錄。


1. Docker 在運作時,出現 Cannot connect to the docker daemon ……

(參考文:https://is.gd/KcNuGL )

Docker Daemon (Daemon=守護程式) ,下會運作 docker.sock .

  1. 而運作的「Docker Service」它所使用的設定檔於: /usr/lib/systemd/system/docker.service
  2. 調整它的ExecStart 執行的屬性資訊:ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock
  3. 重新讀取: systemctl daemon-reload
  4. 重啟服務: systemctl restart docker.service


2. Docker Container 所給予的IP與網域的一樣,會造成Host會有衝突 …

(參考文:

Docker 使用的設定值為:/etc/docker/daemon.json  (in Linux System)  (Windows Docker 我就不知如何更改了)

而這檔案預設是不存在的,所以都是採Default值。

  1. 先查詢目前的Container IP:
    1. 可透過 container 內的 ifconfig :docker exec -it mycontainer ifconfig  (but …通常container內不會裝ifconfig)
    2. 透過原生指令查:  docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' mycontainer
  2. 調整Docker 設定值:daemon.json
    1. /etc/docker/daemon.json   //預設情況此檔案都是不存在的
    2. 加上 { "bip": "192.168.1.1/24" }    //這意指IP範圍為:  192.168.1.1~192.168.1.254
    3. 完整的daemon.json 可看  https://is.gd/YRV4zm
  3. 重啟Docker 服務 :  systemctl restart docker.service


3. 進入Oracle Container後,發現它處理Upgrade的狀態……

(參考文: https://is.gd/K3nhNI – 執行upgrade方式 )

讓Oracle 重啟時,它出現 需要以 Upgrade Mode 運作,而這,就必需讓它執行完 upgrade後,才可以正常執行。

  1. SQL>startup upgrade  , 並執行 Upgrade  (這需要一段時間)
    1. SQL> @$ORACLE_HOME/rdbms/admin/catupgrd.sql
    2. (我一開始還用Linux mode 執行,會出現權限不足的狀況…..)
  2. 執行後:shutdown , 再執行 startup; 即SQL Develop Tool 就可以正常連線了。


PS:若要換sys 的密碼,指令為:ALTER USER SYS IDENTIFIED BY "yourPWD";


後記:

一件單純的Linux 下Docker 的網路概念,就摸了好一陣子,而後再處理Oracle 重啟的議題。

詳細的資訊都寫到筆記上,但相關 Linux / Docker / Oracle 的 指令Keyword  還是要 好好「背」下來才是。


(THE END)

2020/08/10

20200810-職場-工作上還是要寫寫技術心得~So~開始吧

(目前在公司內,寫Blogger,無法貼上圖片資訊)

所以,所做的記錄,還是依「概念」性的資訊為主。

若是要補圖,則 highlight 那一行 要貼上「那一類」的圖示。

然後回家後再來補圖。

-----

我想,重點是在 記錄 接觸 技術上的 心得。

真的,獲得的東西,若沒有寫下來,沒多久就會忘得它「概念性」的觀念。

SO

開始吧!


(THE END)

2020/05/14

20200514-程式-使用.NET Core下NUnit 測試專案的特別事

(為個人心得及遇到特別的怪問題記錄)


採NUnit Test專案的特別事


一、使用的Config,不是app.config,而是固定的「testhost.dll.config」

這一點,花了些時間找出為何它取不到Config 下的AppSetting的資訊

一般UnitTest專案是會定義「app.config」,而在build後,會產生「projectXXX.dll.config」的設定檔,再來使用ConfigurationManager就可以取得到。

但,NUnit的 project 不同,它是固定「testhost.dll.config」這檔案

如何得知?

 ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).FilePath;


2. 要使用ConfigurationManager,則安裝Nuget :System.Configuration.ConfigurationManager。


二、於單元測試下使用HttpClient時,如何加上Header資訊?

使用 httpClient.DefaultRequestHeaders.Add(“XXX”,”OOO”); 即可。

(這一段是將Jwt Token放至於Header之中,以讓Server端可以驗証)


參考文:

c# - Using an app.config file with NUnit3 in a .NET Core console app - Stack Overflow


(THE END) –今日隨意記錄

2020/04/14

20200414-邏輯-取得兩條線的交岔節點

(ref from https://t.ly/mZE5p )

緣起

今天上班在找資料時,看到這此Blog的資訊,疑? 來思考看看如何取得”最佳”結果吧。

而這,感覺就像是 區塊鏈 它的演算法, 要回朔它分岔的節點是那兒?? (只是這圖是反著畫)



題目

知道開頭的節點 資訊, 而假設 上下為 A、B 線。 何時可以找到它們共同的節點。

假設 A在 第M個 節點,與B在 第N個 節點 交岔。

另(A總共有A個節點、B總共有B個節點數)


思考 + 我的解法:

在原Link下,提供了”基本”解法:

方法一、A線全捉出來,B線一個個比對; 這最多需要: (A) 的 B 次方( A數+N ) 次  (取出節點次數)



而我的思考邏輯:

(先說這個沒有看網路答案的~~或許有別種解法)

;則 最多需要: MAX(M,N) x2 –1 次的查詢。  (這算是取出節點次數)


做法:

A、B 輪流取一個節點,並將它放入共同的堆疊裡,

而在放入時檢查,是否已存在? (若已存在,即找到共同的第一個節點)

例如: 放B的第N個節點時,發現已存在,則表示,A 中 M的位置 = 大於 (第一個節點 在堆疊中的 位子 X ) / 2 ) 值的 最小整數。


結論:

當   共同點的數量 > MAX(分岔數量) 時,我的做法才有利。

若   共同點的數量 < MAX(分岔數量) 時,則我的不利 (????)


(THE END)

2019/10/08

20191008-程式-Oracle-處理Table Space相關議題 (Shrink Space)


(趁現在學習後記憶還新,將主軸重點記錄下來)

緣由背景

目前處理Oracle 的資料庫,發生了:ORA-01658: unable to create INITIAL extent for segment in tablespace XXXX 事件。

開始去認識:Oracle 下的 Table Space / 對應的File / Shrink Space概念 (刪除資料後,空間並不會自動釋放出來,而是要再”重組”後才會)


學習後的重點資訊

1. Oracle 資料庫的 資料存放位置概念:

    a. 它不像SQL一樣,就是一個檔案mdf。而是 Table 會有 Partition的概念 (Table Segment ),分成超多份檔案儲存;

        而建立Table  partition 時,指定其「Table Space」,

        而「Table Space」可由很多實體檔案聯集組成 ( xxx.dbf)

        而「Table Space」可以設定 自動擴增(xxx.dbf)(每xxGB) 或是手動處理;這些都會「預占」硬碟空間的;

        而「Table Space」所「預占」出來的空間,會有很多個Blocks(Block_ID),每個Block下有很多Data Block 資料段。

    b. 當「資料刪除」時,該資料所占用的Blocks區段,並不會自動釋放出來。

        所以要透過 Shrink Space(縮小空間) 處理來重排釋放出空間 (如同電腦下的硬碟重組 )


2. 要做的事情動作流程:

    a. 要知道目前Oracle 下有那些的Table Space及其對應的實體Files及使用狀況: https://bit.ly/2MlldTj

    b. 查出有問題的Table Space,要知道目前有那些 Table 使用,並查出那Table 占用最多:  https://bit.ly/2OxhIvF

    c. 針對目標Table 刪除資料 。(此篇文就完整說明整個流程及block資料check:https://bit.ly/30Z0zNT )

            1) 刪除資料後,要執行 PL\SQL 程序,它才會重計算Row Count

                     SQL> execute dbms_stats.gather_table_stats('XXXUser','XXXXXXTable');

            2) 開始執行 「Shrink space Or Shrink space compact 」的動作。

            3) 要先啟用 Table Row movement 。

            4) 執行 Shrink Space :   SQL> alter table XXXUser.XXXTable shrink space;

                 執行完,一樣要再執行  PL\SQL 程序  (資料量大則很費時)

            5) 執行完後,再查詢其 Block 資訊清單,則可看到其數字會下降

            6) 再 關閉  Table Row movement


參考重點文:

(THE END)

2019/09/12

所有文章列表


20151129-fixed-讓它可以show全部post
------------------
------------------
------------------


2019/06/26

20190626-程式-讀了別人技術文件後的特別之處(未寫完)

(這是目前公司需讀的一份技術文件)

當然我這篇也不是要全部記錄內容,而是將幾個對我的技術思考有所”衝擊”的部份,捉出來做記錄。

加上自已的”心得”。


此乃參考了此作者:Harry 的資料 (他原在目前公司工作,今年才離開)


Effective C# 條款一: 使用屬性代替公有欄位 | Level Up

>>   

這額外的好處,是可以   a. 加上lock(this)的機制 (可執行於多執緒)     b. 可以輕易的加上 EventHandler (方便外部override)

    ex:

public event EventHandler  NameChanging;
public string Name{
set { _name = value ; NameChanging (this,new EventArgs());}}
//這樣就可以讓外部控制了。

Effective C# 條款二: 運行時常數優於編譯時常數 | Level Up

a. 編譯時常數 (Const)  vs  運行時常數 (ReadOnly)

b. Const 會在”編譯”過後就被換成常值。

c. 效率 Const > ReadOnly  ; 彈性  ReadOnly >Const


Effective C# 條款三: 運算子is或as優於強制轉型 | Level Up

a. 型別轉換: ( o as MyClass)  >(優於) > ((MyClass) o)  ;因為 安全/效能 ,不用加try … catch。

>>我還真不知有這樣的差異。


Effective C# 條款四: 使用ConditionalAttribute替代#if條件編譯 | Level Up

[Conditional(“TRACE_ON”)]

Effective C# 條款六: 明辨值類型與參考類型的使用場合 | Level Up

Effective C# 條款七: 將值類型盡可能實現為具有常量性與原子性的類型 | Level Up


Effective C# 條款八: 確保0為值類型的有效狀態 | Level Up

Effective C# 條款九: 理解幾個相等判斷之間的關係 | Level Up

Effective C# 條款十: 理解GetHashCode()方法的缺陷 | Level Up

Effective C# 條款十一: 優先採用foreach迴圈 | Level Up

Effective C# 條款十二:變數初始器優於賦值語句 | Level Up

Effective C# 條款十四:利用建構子鏈 | Level Up

Effective C# 條款十五:利用using和try/finally語句來清理資源. | Level Up

Effective C# 條款十六:盡量減少記憶體垃圾 | Level Up

Effective C# 條款十七:盡量減少裝箱與拆箱 | Level Up

Effective C# 條款十八:實現標準Dispose模式 | Level Up

More Effective C# 條款四十九: 考慮為大型物件使用弱引用 | Level Up



C# 技術

1.用屬性(Property)代替欄位(Field)

2019/03/20

20190319-剪輯-第二次用威力製作的心得(花很多時間)

(這次所做出來的成品)

資訊彙整&前言:

這次製作的成品,就是這一部影片

上一部製作文章心得: 20190315-剪輯-初次使用威力導演製作的結果&心得記錄


前言:

這一次,主軸不是在「創新」製作,而是將 上一次的製作流程,讓它能有效率。

而且此次的影片,增加了「回程」的影片內容,檔案大小一整個變大超多!(1個多小時,大小35GB)

而先記錄一下此次處理的順序流程。


此次處理流程 & 時間軸:


【處理順序】:

1. 晨騎回家先將 VIRB copy 至電腦 (有四段影片)  (35G,copy 半個多小時)

  (此時拉筋&冰敷&小睡片刻)

2. copy至電腦後,開啟「威力導演」,做「防震優化」 (四部影片)

  (當下是利用空檔寫寫運動日記)

3. (四部影片)透過「VIRB Edit」匯入功率資訊並對應Map,合併影片後匯出一部 (都沒有剪掉沒用段)

    (這一段,就是完成素材,而匯出會等很久……)

4. 開始使用「威力導演」編輯內容 (一部影片)

5. 標記每一段的時間點的標籤上去

     (這段其實不用做,因為 影片一剪輯後,標記位置都會跑掉!!所以之後直接「切下斷點」)

6. 切下斷點

6a. 刪掉沒有必要的影片段 (要保留一些供轉場用的,留10秒為單位)

     (全部一次切完/刪除完,這會花很多時間)

7. 處理「護士坡x4」爬坡影片,截掉不要的影片段

     (建議先截再搬,不然影片會被蓋住,不好處理)

8. 搬移「護士坡x4」爬坡影片至另外三軌道

9. 可直接做掉 護士坡的 排版&特效

     (利用四個子母畫面處理)

10. 加入片頭動畫

11. 加入每段的「標題文字」動畫 / 「串場時間」動畫

     (先不要加上轉場特效)

12. 加上轉場特效 (隨機 / 標題動畫也一同加)

     (a. 路段=>串場時,b.串場=>路段時,自已本身內的轉場不要加)

13. 補上「領騎段」的動畫

     (直接看影片,看那段人領騎,就直接做上去)

13a. 若要玩追蹤效果,就在此時處理

14. 開始估算出每一點的開始時間

15. 加上時間軸字幕(依文字長度而分段)

16. 依各路段切開時間軸

17. 為切開的時間軸,加重目前所在的路段位置

18. 不要再加上中間文字註解,不然我會做不完XD

    (除非你真的很閒)

19. 匯出檔案 (威力匯出時,不會很久,濃縮成30多分後,匯出10幾分就可以了)

20. 上傳影片至Youtube

     (這需要很多時間(半小時??),就放著) (這一次是弄到晚上11點才上傳!然後等到它好後,將它貼至Line/FB社團上)


我做影片的目的


當然希望很多人可以觀看, 或是做出 別人想要觀看的影片

但,最主要的目的是:

我要察看我的騎車功率/迴轉速的變化

這才是最核心我要花這麼多時間做的價值。


日記、記錄,所花下的時間都應該是這個,一定要對我目前的目標有所幫助!

犧牲掉 訓練/收操 的時間,一定要有它的效益才行。

不能僅是花時間看看 FB / Line ,然後期望得到掌聲這類的收獲。


再加油了。

(THE END ~一早花2HR來寫寫此次的製作流程 &心得)

2019/03/15

20190315-剪輯-初次使用威力導演製作的結果&心得記錄

(這是這一版製作的最後結果)

(註:此篇不是教學文,僅是自已的使用心得記錄)


資訊彙整:

結果影片:



這一次製作達到的重點摘要:

一、製作了封面特效。

二、加上了路段的標題 / 領騎的特效  (可以移動特效的位置)

三、利用「標記」標下各段的重點,方便剪輯。

四、使用「子母視窗」分割「爬護士坡x4」的畫面。

五、加上「時間軸」的側欄文字。

六、有看加字幕怎麼加比較快 (此片沒有加)



就這樣買下威力導演旗艦版!

收到正版軟體的記錄



緣起:

因為前一陣子,又重新使用「運動攝影VIRB」,而想後製時,威力導演試用版,是無法彙入影片:

(官方試用版,限制說明:http://bit.ly/2VZWIhE )

導致我沒有辦法處理影片,而也不可能都是透過手機在進行。 就這樣!心一橫,就把它買下去了!(有花些時間比價)

購買的資訊,找到有特惠的版本:折了$600元。(星期六下單,星期二收到貨~)


開始使用的心情疑問:

一開始使用,最基本想要知道的事:

一、如何弄出「子母畫面」?

二、怎麼加上「封面」?怎麼加上「文字特效」?

先讓自已從最基本的開始。

開始每一項的特效說明記錄。


剪輯-封面特效

這是直接使用「文字工房」下的,而它的位置,剛好是我所需要的,這樣搭下來的結果我很喜歡


剪輯-製作路段的子標題

(最後結果圖)

我使用的為此「文字特效」

但因為它的「位置」不是我想要的!(我一點我花了不少時間才找到如何編輯?)

首先:

1. 進入該特效的「文字設計師」。

2. 在這畫面,移動文字是OK的,但要移動底圖,就要靠「炫粒設計師」下去操作 。(一開始一直沒注意到右側有ScrollBar,害我找好久~)

如此一來,就可以編輯,移至所要的位置,並將它「儲存為樣版」,方便之後的使用。


剪輯-使用子母畫面

一開始還以為這很難,但這超簡單的,只要利用多個軌道處理即可。

(最終結果圖)

利用多軌道處理

調整每個影片的比例大小,放至對應的位置,就出現「子母畫面」效果; (子母畫面設計師)

再來再自已補上:

a. 爬坡訓練的中間特效文字。

b. 每一趟的費時時間資訊。


剪輯-加上時間軸文字

這邊期望的效果是:在那一個時間路段下,它的「字體就會自動加粗」。達到可提醒 觀看者,目前在那一個段落。

這邊最終採用的作法,變成寫好「時間軸」資訊後,然後在各時間點下「切割」,然後再各自「加粗」該段文字。(不知有無較好做法?)

(自已切割時間點)

修改它的文字樣式;(本以為可透過「關鍵畫格」,在處理它的文字變化,但「關鍵畫格」只可處理-位置/比例/… )


剪輯-最後自已定義的文字格式

訂出這幾樣,以後製作時,就可直接拿來用了。


結論


初次使用,然後製作出達到自已想要的畫面,那感覺很棒!

依照自已腦子內所想像的,然後找出它關鍵的實作技術,就跟寫程式一樣,對於每項工具,先有需求,然後再找方法將它實作出來。

這樣的學習是最有效的。

相較之前一直想學影片剪輯而遲遲沒有動手

而這次,就直接「購買」,直接「應用」,

發現「剪輯影片」並沒有想像中的困難。

加油!

持續隨心所欲,學自已想學的東西,別被受限住了。


(THE END ~3/15 一早5點起來把這篇寫齊~~1.5HR)

2018/12/18

20181218-程式-C# Enum 列舉的超級應用 整理

image

(這就是此篇最 “複雜”的Enum應用結果示意:使用Char定義、且可以序列&反序列化) (ref from :http://bit.ly/2LnBjLc)


緣起:


什麼是列舉的最佳寫法?「Value To Enum」、「Enum To Value」

在寫Enum轉換時,總是會做下述的判斷:

a. 判斷value是否在定義之中? (Enum.IsDefine(xxx))

b. value Parse為Enum (Enum.Parse)

而這之中,是有「陷阱」的! (請繼續往下看…..)

因此,整理這一篇 針對 Enum 的程式開發 技巧。


使用情境:


基本模式:

資料庫的Type欄位,有1、2、3 等數值型的資料,

而在程式開發時,想要用 列舉 Enum 規範住 所允許的 範圍值。

進階模式:

資料庫的Type欄位,有 A、B、C 等非數值型的字元資料,

而在程式開發時,想要用 列舉 Enum 規範住 所允許的 範圍值。



重點:


■  基本的Enum判斷 &寫法 (基本款)

■  進階的Enum使用Char的定義方式之 判斷&寫法 (進階款)



基本模式 - 值與列舉的轉換


public enum MyEnum{

      None,

      Item1,

      Item2

}

基本的判斷方式(db欄位值轉為Enum):

Var dbValue = 1;
var myEnum = (Enum.IsDefined(typeof(MyEnum), dbValue) ?
                     (MyEnum)Enum.Parse<MyEnum>(dbValue.ToString()) :
                     (MyEnum.None));

基本的取值方式(Enum轉為db欄位值):

var dbValue = (int) model.XXXX;


基本模式 – Enum.IsDefined(xxx) 的陷阱 - 要輸入”數字”的


這就是Enum的陷阱!!!

(Enum.IsDefined(typeof(MyEnum), 1)    //true
(Enum.IsDefined(typeof(MyEnum), "1")  //false 


就是 Enum.IsDefined(  ) 內部的參數值,是要「數字」的!!不然它都會 get false .


基本模式 – Enum.Parse(xxx) 的陷阱 - 要輸入”文字”的

Var dbValue = 1;

(MyEnum)Enum.Parse<MyEnum>(dbValue.ToString())


進階模式 - 使用「Char」來代表列舉值


(這還不是正確寫法)

public enum MyEnum{

      None = ‘-1’,

      Item1 = ‘A’,

      Item2 = ‘B’

}

(正確寫法 - 這樣Json序列化 才可以傳入 ‘A’字串)

using System.Runtime.Serialization;
[JsonConverter(typeof(StringEnumConverter))]
public enum MyEnum{
       [EnumMember(Value="-1")]
       None = '-1',
       [EnumMember(Value="A")]
       Item1 = 'A',
       [EnumMember(Value="B")]
       Item2 = 'B'
}


進階模式下 - 使用 Enum.IsDefined(XXX)

一定要轉成為Int

Enum.IsDefined(typeof(MyEnum),(int)'A')


進階模式下 - 使用 Enum.Parse(XXX)

一定要轉成為字串

(MyEnum)Enum.Parse<MyEnum>(((int)'A').ToString())



進階模式下 - 整合應用


var dbValue = (int)Convert.ToChar("A"); //先轉為Char,再轉為Int
Enum.IsDefined(typeof(MyEnum), dbValue );  //true
(MyEnum)Enum.Parse<MyEnum>(dbValue.ToString())


判斷方式(db欄位值轉為Enum):

var dbValue = (int)Convert.ToChar("A"); //先轉為Char,再轉為Int
var myEnum = (Enum.IsDefined(typeof(MyEnum), dbValue ))?
                             (MyEnum)Enum.Parse<MyEnum>(dbValue.ToString()) :

                            (MyEnum.None));


判斷方式(Enum轉為Db欄位值):

var dbValue = ((char) model.XXXX).ToString();  //got “A”


這樣的寫法,就可以取得它的字元值

clip_image001


(THE END)

2018/12/06

20181206-程式-knockout 搭配 Fileupload 的思考過程記錄

20181206-上傳檔案結果

(一整個上傳檔案的流程結果:編輯>選擇檔案>挷定在頁面上>更新儲存>測試下載>成功>再編輯>刪除已存在檔案>完成此流程)

(第一次使用git動畫圖示意~~)

(使用技術:ASP.NET MVC、Knockout 、FileUpload (knockout-file-bindings Framework) ….)


情境說明


就這一次的技術需求:

「編輯時可上傳檔案,於儲存時,將檔案儲存起來」(呈現檔名/檔案大小)

是的,需求就是「這麼的簡單」。

而在技術實作上,我也要盡量做到「操作簡單化」的方向前進。

這之中遇到的思考問題還真是多呀!


而 先解決 Service 端針對檔案的儲存實作。使用Byte[]的方式來做為 串流的傳輸。


再來,就是著重在前端Client 與 Web Server之間的傳輸處理。


思考的問題有下列:(針對檔案處理的部份)

■  為了讓使用者操作方便,採用Knockout 的開發模式,而檔案部份,期望如上圖模式的動線。

■  我如何先將現在的檔案清單 以Knockout呈現? 並可以供下載 ?

■  Client端的 FileUpload 它的原理?不是很熟。

■  Client端的 File 串流,如何Post 至 Server端? MVC的Action要如何的接??

     我可以利用現有的Model直接post 整包回去Server端嗎? 重點是我要在 Knockout 的架構下實作

■  在上傳檔案後,於使用者按下「儲存」前,我不想將檔案 先暫存於Server端 (原本有思考這樣的模式,but….)。

    而是在他點選「儲存」時,我再一併去儲存檔案。


開發處理流程


記錄下自已依序實作的重點項目,一步步的將這一份需求完成:

一、Server端的服務應用,先可以完成 新增/更新/刪除 檔案的動作,其中包括:

       a.  思考傳輸所用的 Contract 如何設計?

       a.  依儲存規則儲存檔案。

       b.  更新時,整包Model參數傳上來時,針對檔案的部份,決定是採 新增動作?還是 刪除動作?


二、前端 Detail的呈現,加上了「檔案」的資訊,其中包括:

      a.  呈現檔案清單時,只保留Key值資訊,而點選後,另一個Action 單純處理下載檔案的功能。

      b.  使用Knockout 的挷定呈現。並加上HyperLink 點選時可以下載檔案。


三、檔案上傳的功能,並可以挷定至Knockout,且可以Post串流至Controller接受端,其中包括:

     a.  Client端的檔案上傳,它的串流是如何取得?這是我不懂的一塊邏輯。

     b.  因為我是直接用整個Model 傳輸,所以,它byte[]的型別 可以接受嗎??

     c.  檔案上傳後的動作,我透過「knockout-file-bindings」(link) 來達到此功能,好處是:

               1) 原來開發操作這麼簡單  (官方範例:(Link))

               2) 很容易取到它上傳的檔案資訊(檔名/大小/…)、檔案串流(base64String)   (我若用原生的方式取得 byte串流,效能很差 )

               3) 它post 回 controller,可以直接 使用 byte[] 屬性 接受串流的 (使用 base64String的資訊)。 (超有幫助)


就這樣,完成這樣的實作過程!!


重點程式碼結果說明(檔案上傳部份)

(原本的blog coding style css 沒有生效@@,僅能先貼程式碼上來啦~)


//Html的檔案上傳元件

<!-- ko if: ($root.IsEdit()||$root.IsCreate()) -->
        <input type="file" multiple data-bind="fileInput: multiFileData" />
<!-- /ko -->


//檔案清單的呈現區寫法(Knockout)

<div data-bind="foreach:FileInfos" style="max-height:100px;overflow:auto">
                   <div class="col-md-12">
                      <!-- ko if: ($root.IsEdit()||$root.IsCreate()) -->
                       <div class="col-md-2">
                           <span class="glyphicon glyphicon-remove onpath" data-bind="click:removeFileInfo"></span>
                       </div>
                       <!-- /ko -->
                       <div class="col-md-10">
                           <a href="#" data-bind="text:FileName,click:downloadFileInfo"></a>

                          &nbsp;(<span data-bind="text:FileSizeDisplay"></span>)
                       </div>
                   </div>
               </div>


//於Script區 ,定義了其multiFileData,這樣才可以在它有變動時,觸發我想做的事

viewModel.multiFileData = ko.observable({
         fileArray: ko.observableArray(),
         base64StringArray: ko.observableArray(),
         dataURLArray: ko.observableArray(),
     });


//當檔案選擇時的觸發事件時,我要將資料加入至「viewModel.FileInfos」,而其中的「content」資訊就是挷定其byte[]資料

//使用knockout-file-binding,但它「base64StringArray.subscribe若上傳4個檔案,它會觸發4次

viewModel.multiFileData().base64StringArray.subscribe(function (base64StringArray) {
          console.log("call:" + base64StringArray.length);
          if (base64StringArray.length > 0) {
              var last = base64StringArray.length - 1;   //因為觸發多次關係,所以僅取得每次的最後一筆
              var fileInfo = viewModel.multiFileData().fileArray()[last];
              var base64String = viewModel.multiFileData().base64StringArray()[last];
              addFileInfo(fileInfo, base64String);
          }
      });
      function addFileInfo(fileInfo, base64String) {   //加入至 FileInfos的陣列中
          var name = fileInfo.name;
          var size = fileInfo.size;
          var kofile = ko.mapping.fromJS(initFileMaintainModel);
          kofile.FileSizeDisplay = ko.observable("");
          kofile.FileName(name);
          kofile.FileSize(size);
          kofile.FileSizeDisplay(fileSizeDisplay(size));
          kofile.Content(base64String);
          viewModel.FileInfos.push(kofile);
      }

     function fileSizeDisplay(FileSize) {    //將檔案大小轉為/MB/KB/byte的模式呈現
          var result =
              (FileSize >= 1024 * 1024) ? Math.ceil((FileSize / 1024 * 1024 )) + " MB" :
                  (FileSize >= 1024) ? Math.ceil((FileSize / 1024)) + " KB" :
                  (FileSize) + " byte";
          return result;
      }

//而儲存時傳送Ajax回去的參數處理

        JSON.stringify(ko.mapping.toJSON(viewModel))

而使用Ajax傳送時,這個contentType很重要,意思是指:將傳送的參數當json結構處理

image

則Post 回 MVC時,就可以直接使用Model接收的:

image

而其中的檔案串流,我Model採用 byte[] 型別,是可以接收的。 (client端直接取得其  base64String 即可)

image


剛上傳的檔案,要再直接讓使用者下載


在 User 未儲存前,其剛剛上傳的檔案,點選其Link,又要讓User可以下載 剛剛所上傳的檔案,

這需求,因全在Client端操作,這個想法需求 又讓我 「學了一關」 了!


而這主要的概念動作為:

     a.  透過base64String 產生 Blob() 串流資訊

     b.  透過 Url.CreateObjectURL(blob) 產生 暫時用的 連結。

     c.  若使用 window.open (url)的方式開啟,可下載,但檔名無法定義。

     d. 若使用 <a> 下的download 屬性,可以指定它的「檔案名稱」。



//從base64String 轉換為 Blob的函式


         // http://bit.ly/2Pp9K4N
         function b64toBlob(b64Data, contentType, sliceSize) {
             contentType = contentType || '';
             sliceSize = sliceSize || 512;

            var byteCharacters = atob(b64Data);  //將base-64 解碼(decode)為字串
             var byteArrays = [];

            for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
                 var slice = byteCharacters.slice(offset, offset + sliceSize);

                var byteNumbers = new Array(slice.length);
                 for (var i = 0; i < slice.length; i++) {
                     byteNumbers[i] = slice.charCodeAt(i);
                 }

                var byteArray = new Uint8Array(byteNumbers);

                byteArrays.push(byteArray);
             }

            var blob = new Blob(byteArrays, { type: contentType });
             return blob;
         }


讓使用者下載的方式

             var name = item.FileName();
             var mimetype = item.MimeType();
             var content = item.Content();
             var blob = b64toBlob(content, mimetype);
             var blobUrl = URL.createObjectURL(blob);      //透過Blob建立下載的Url,若是用window.open()則無法指定檔名
             //透過<a>來指定下載檔名
         var a = document.createElement("a");
             document.body.appendChild(a);
             a.style = "display: none";
             a.href = blobUrl;
             a.download = name;     //指定FileName
             a.click();
             window.URL.revokeObjectURL(url);      //消除url
             a.remove();


MVC無法傳送大量的JSON資料?

因為我需上傳 大於1MB的檔案,而得到此錯誤。

遇到此Error:

System.ArgumentException: Error during serialization or deserialization using the JSON JavaScriptSerializer. The length of the string exceeds the value set on the maxJsonLength property.


網路上查的解法是:

<configuration>

<system.web.extensions>
        <scripting>
            <webServices>
                <jsonSerialization maxJsonLength="50000000"/>
            </webServices>
        </scripting>
</system.web.extensions>

</configuration>

但這是沒有用的!!這指的是 Server端 傳回給 Client端的最大Json 長度。


而我需要的是: post json data to MVC action

最終的解決方式:

僅能去改寫原本 MVC5 的 JsonValueProviderFactory 的程式碼:  (官方原始程式碼為:http://bit.ly/2Pn5OBn )

JavaScriptSerializer serializer = new JavaScriptSerializer();
serializer.MaxJsonLength = int.MaxValue;


調整完後,再於 Application_Start 下,改掉它的Factory:

//howard:增加 request Json length
             ValueProviderFactories.Factories.Remove(ValueProviderFactories.Factories.OfType<JsonValueProviderFactory>().FirstOrDefault());
             ValueProviderFactories.Factories.Add(new MyJsonValueProviderFactory());



(THE END)

2018/11/21

20181121-程式-使用Knockout呈現資料過程+moment.js處理日期呈現

image

(先寫出第一版,點選樹狀資料,在右側會呈現其結果資訊)


重點記錄:

(此篇不是記錄基本的使用,而是過程中遇到的問題)

■    Knockout在處理具有 subModel的物件時,它的Bind方式是要借用「data-bind="with:ArchiveFolder"」方式處理。

■    C#回傳的Json日期格式為「CreateTime":"/Date(1542789732383)/"」這類格式。

      而透過moment.js 可以轉換為正確的日期格式。


參考資源:


■    Knockout 的with binding 處理說明:

      https://knockoutjs.com/documentation/with-binding.html

■    Moment.js 的日期格式處理: (官網也在這)

      https://momentjs.com/docs/#/parsing/string-format/

■    相關的問題:problem knockout js with date binding


1. Knockout 處理子Model 議題:


這是我物件結構的樣子:

SNAGHTML63a6538

當我要Bind Name 的屬性時: data-bind就是要這樣寫

<div class="col-md-9" data-bind="with:ArchiveFolder,visible:IsView">
                    @Html.SpanFor(m => m.ArchiveFolder.Name, new { data_bind = "value:Name" })
                </div>


2. 使用Moment.js處理Date格式

最終就是用這方式,處理JSON回傳的「CreateTime":"/Date(1542789732383)/"」日期格式

image


(THE END)

2018/11/15

20181115-程式-設計具有新欄位Mapping的架構設計邏輯

image

(目標設計架構結果圖)


設計需求背景:

*

當從資料庫取得的Table 欄位資訊,在應用至程式開發上,也許需將它「重命名」為具有意義的「新命名」(滿足命名規則)。


因為這樣,在現行的功能下,我想要加上這樣的功能,且「不能設計太復雜」 XDDD。

而這次的處理,很多技術的問題,在於前端Json Array 的處理,太多技術細節的應用都需上網查詢如何用?

因此,也將這樣的資訊Log 下來。

*

主要就是「原欄位名稱」,具有個地方可以修正,讓它可以 Map 至新欄位資訊。

這樣的好處,是在產生 程式碼時,都可以有 一致性 的命名。而不會受限於於原本的資料表 Naming。


設計需求概念-Column Mapping

這邊,就將技術需求面,做個整理描述,方便未來可以 回味

*

1.  對應的資料儲存,直接以Json格式儲存即可。

2.  當它在選擇 各類Table時,它的欄位對應清單,就會一直做累加的動作。 且已存在的名稱,就 不重覆 新增至清單車 (以便一致的命名規則)。

3. 當它選擇到「A Table 」時,欄位Map清單中,與A Table 相關的欄位會「自動」排序在最上面。  (這需求超棒的!)

    (超級 友善 的操作動線 !,方便針對 A Table 的欄位做Mapping  )

4. 取得 & 儲存時機點:在 Load Database時 取得Mapping 清單; 在 Generate時 將現在的Mapping 清單 儲存。


技術面的參考資源彙整:

1.  Javascript  Array 上的相關應用:  超完整內容&都有範例  (https://mzl.la/2OKVDpU)。

     --應用到:array.splice (拼接)/ array.slice(0) (複製概念) / Array.reverse()(反轉) / Array.find(func) (找到滿足之Element) 

        Array.some(func) (檢查是否存在?)


技術面的開發過程:


預期的JSON儲存格式:

image

a.   JSON資料的初始字串為「[]」才是表示Array,(而示是「{ }」代表),而在後續的應用上,才會正確。

b.   資料目標,在Client去應用處理 ,Server端只負責「取全部」「存全部」即可。 (也就是這樣,我在Client 端有大量的Array 處理應用~)


最終結果的JS程式  (Angular框架下):(截錄最重要的Function)

image

a.  這是傳入所取得的Table Column ,然後依判斷,再決定 新增 / 或是「搬移」現有的 最終程式碼。

*

再來就依續說明,程式設計原因:

Array 的 Copy 及 反轉(Reverse):

image

a.  為了不影響現在的Array,所以要先Copy一份出來做處理。

b.  因為 要將有滿足的ColumnName,在處理過程中都填入至「第一筆」,所以我將Array反轉處理。 (邏輯思考)


找到滿足條件的Element  (再加上取得它的Index位置)

image

a.  Array 下 Find()的應用,它是傳入Function的,且還可以用 Lambda的語法寫 (javascript 竟可跟C#超像)

b.  因為無法直接取得該Element所在的Index,所以透過Find的過程中,將Index記錄下來。


若找到Element,開始做排序動作,將它「搬移」至最上層

image

a.  這需求:要達到將原Array下的Element搬移至最上頭,所用的解決方式:splice 處理。先移除/再新增至第一筆。

b.  splice的使用概念:目標位置,要移除幾個 、要加入的元素 (也可以是Array)。


結論心得:

*

針對前端Array 的這類 較細的應用,實在是要花時間在尋找「解答」。

不過,最重要的是「怎麼設計出好的需求應用」。

*

現在要學習,記錄下「技術文章」內容,雖然有時是較細的技術,但是後續要可以看得懂我原本的「思考流程」概念。

再加油了。

(THE END)

2018/11/09

20181109-程式-C# 使用 DotLiquid 透過Template定義產生 其程式碼資料

SNAGHTML57880445

(最終所產生的目的結果:將資料庫的Table資料,產生對應的Class資料)  註:因table資訊未補齊,所以結果圖才會小怪怪的。


目標

依所取得的 Database Table 下的Columns資訊,可以依 「Template」的定義,決定其 Render出來的Class樣式。


此篇重點:


■    目標是要能夠讀Template定義資訊,然後產生對應的Code Result。

■    使用「DotLiquid」的Framework,以及所遇到的問題及心得!(真出呼我意料之外)

■    此篇思考了:如何不動到原Model,又可以應用至DocLiquid當參數的方式。

■    DotLiquid它是無法直接使用即有的Model類別物件的,最終都會是使用 Anonymous Class (匿名物件)

http://bit.ly/2RNhQWt (官方說明)

clip_image001

註:實作 ILiquidizable的函式,最後也是回傳 匿名物件的。



彙整相關資源:

■    Liquid 語法的官方說明  (DotLiquid為實作能讀取該類Template 的Framework)

■    DotLiquid的官方網站DotLiquid的 GitHub資訊它的Wiki資料(那幾篇都要看)

■    DotLiquid的 Template官方測試案例  (使用Sample)

■    Dot Liquid Template Implementation in C# and MVC

      >>我並非用此篇內容,僅是參考別人的寫法如何寫 Dot Liquid的程式碼。


最終程式碼模樣:


定義的Liquid樣版資料:

image

  • {%- -%} 多一個「-」號的用意,是Render時不讓它多占一行空白資料  (官方語法說明:http://bit.ly/2RIUWzh )


實作出DotLiquid實務上應用的程式碼:

image

  • 讀取特定的樣版資料。
  • Template Parse 該資料內容,建立起 Liquid Template。
  • 使用 Liquid 可以用的Model:實作 Liquidizable。
  • 若要透過Object,最後一定都是要呼叫:Hash.FromAnonymoutObject。


最終使用的Model模式:(採用繼承原Model後去實作ILiquidizable)

image

image

>>這最後也是回傳「匿名物件」出去。 (這邊即是定義Liquid Template可使用的參數)




遇到的問題:


錯誤一:Liquid syntax error: Object 'CodeGen.Web.Models.TableInfo' is invalid because it is neither a built-in type nor implements ILiquidizable

這就是「TableInfo」對DotLiquid來說,不是匿名物件型別  (實作ILiquidizable的程式可參考上面)

而加上 Template.RegisterSafeType 的方式,它也是要明確宣告要那一個 Property Name,所以我實務上不這樣做。


錯誤二:Missing property. Did you mean 'column_description'?

它不是Exception,而是在Render時,它認不得所用的屬性,

最終就是 上述程式的寫法 解掉這問題。

總之,它Render可讀的參數類型,以C#來說就是 Anonymous Type 的資訊了,(且還不能讀Json資料當參數……)


個人學習過程心得:


1.

過程中,使用 Dot Liquid的方式,真的概念和我不一樣。

原以為,就是傳入 DataModel,及使用對應的Template,它就可以Render出我要的資訊出來。

但……就是不能使用原生的DataModel,要變成用匿名物件、或是實作他的ILiquidizable 介面。


2.

網站上的資訊,很少有寫DotLiquid的使用方式,

這次就 嘗試出 這樣的寫法架構,不要修改到原生的Model,而可以當DotLiquid的參數使用。

而看官網的 「單元測試」,看看他們怎麼寫,也是不錯的經驗

(THE END)

2018/08/17

20180817-技術證照-C# Tutorial Certificates

20180817-1526003

the certificate ref from SoloLearn:https://www.sololearn.com/Certificate/1080-10462479/pdf/

緣起:

星期四晚上,發現這一個教學app:SoloLearn

官網:https://www.sololearn.com/

[ Google Play] https://play.google.com/store/apps/details?id=com.sololearn

它具有各技術主題:C#、SQL、Java….

而一步步的教學 &測驗 (有導入那種 解鎖關卡 的機制)

而就這樣,個人使用C#的語法,已非常習慣,就直接依照它的Tutorial課程,直接「上場測驗」

這之間,有幾題是自已了解觀念不夠深,將它LOG一下這資訊。


考題:遞增運算子(++)

image

解答參考: ++ 運算子 (C# 參考)

1) b =a++; 先將 a 未加之前的值,給b。  (而在下一行的執行,a才會再加一)

2) ++b,是b先加一再列印出來。 所以解答是:4+1=5

=============

這個是「遞增運算子」,讓我當下考試時 呆了好一陣。我知道放至 運算元  放前/放後 是有所不同的。

但未記得它的差異處是。

前置遞增 / 後置遞增 的模式,

 image


20180816-2317044


它的問題類型 及 PK模式

條件式運算子 || 、&&

20180816-2320028

[||運算子] https://docs.microsoft.com/zh-tw/dotnet/csharp/language-reference/operators/conditional-or-operator

[&&運算子] https://docs.microsoft.com/zh-tw/dotnet/csharp/language-reference/operators/conditional-and-operator


它可以依經驗值,即時PK

20180816-2326040

>>後來是 2:2平手,有幾題我答錯了。 且 題目的解讀 有些緊張的。


記錄下有意思的題目


Try Catch Finally 的議題

20180817-1450003

X/=x :它等同於  x = x / x  。 所以 它是會拋Exception的 (不可以除於零)

而跑至Catch下,且 最後會執行Finally區段

故解答為:7


抽象類別的繼承

20180817-1451030


解構子的問題

image


列舉的給值,它是會再接續下去的

image

>>它的答案為:6

>>會記錄這題,是有些疑惑,它初始從0開始,若中間給值,它是再接續下去?還是?


再來就是順利解鎖 相關的測驗,拿到了此篇證照


20180817-1526003


非常有趣 / 挑戰性的App,可惜 它沒有 TypeScript / Angular 相關的一步步課程學習。

(THE END)