express vue-demo-sample --view ejs --git cd vue-demo-sample npm install
這樣我們的 Web Server 就可以啟動了,使用 VSCode 直接開啟 vue-demo-sample 目錄,然後開啟一個終端視窗,啟動 Web Server。
1
npm start
從流覽器開啟 http://localhost:3000/ 你就可以看到 Express Server 的起始畫面,這個 Web Server 就將是我們 Web Application 的伺服器,我們可以開始使用 Vue.js 開發前端程式了。
開始 Vue.js 之前我們先來了解一下伺服器端的架構與運作方式。
public 目錄是 Express 靜態檔案服務的根目錄,所有需要下載到流覽器前端的程式碼,都會放在這個目錄下,當你從流覽器開啟 http://localhost:3000/ 時,它會對應到 Express Server 端的這個 public 目錄,然後尋找 index.html 並下載到流覽器渲染成我們所看到的畫面。在 SPA 架構中,這幾乎是我們會從伺服器下載的唯一一個 HTML 檔案,我們也將從這裡開始 Vue.js 的旅程。
但在 Express 的 public 目錄中並沒有發現 index.html,這是因為 Express 使用伺服器端的模版(這理使用 EJS,EJS 是一種簡單的模板語言,可讓您使用純 JavaScript 生成 HTML 標記)動態產生一個 index.html,你可以在 views 目錄中發現這個模版 index.ejs
type Employee { empno: ID! ename: String job: String mgr: Int hiredate: String sal: Float comm: Float income: Float department: Department }
type Department { deptno: ID! dname: String loc: String employees: [Employee!]! }
其中 empno 在資料庫是 Number(4),這裡可以設定為 Int!,但我們為了確保回傳唯一值,將它設為 ID!,但要記得純量型態 ID 是一種字串型態,相對的 mgr 欄位就必須有所取捨,Int 或 String? department 欄位則不存在 EMP 資料表中,這裡我們則設定了一個一對一連結,返回 Department 資料型態。 income 則會是 sal 與 comm 相加的值,我們可以在此朔造資料庫端與使用者介面端的橋樑。
Department 型態的欄位 employees 回傳一個 Employee 型態的串列,這是個一對多連結,它可以回傳空陣列 [ ],要記得,空陣列在技術上不是 null,它是不包含任何值的陣列。
現在我們可以 query:
query
1 2 3 4 5 6 7 8 9 10 11 12
query { employee(empno: "7788") { empno, ename, income department { deptno, dname, loc } } }
query { Lift(id: "jazz-cat") { name status capacity night elevationGain trailAccess { name difficulty } } Trail(id: "river-run") { name difficulty accessedByLifts { name status capacity night elevationGain } } }
這個查詢請求的是 Jazz Cat 纜車與 River Run 雪道的資訊。Lift 的選擇組裡有 name、status、capacity、night 與 elevationGain。我們想要取得的 River Run 雪道資訊有一些欄位與 Lift 型態的欄位相同。我們可以建立一個 fragment 來協助減少 query 重複的地方:
1 2 3 4 5 6 7
fragment liftInfo on Lift { name status capacity night elevationGain }
我們用 fragment 關鍵字來建立 fragment。fragment 是屬於特定型態的選擇組,所以你必須在 fragment 的定義中指定它所屬的型態。這個範例的 fragment 稱為 liftInfo,它是 Lift 型態的選擇組。
當我們要在另一個選擇組中加入 liftInfo fragment 欄位時,可在 fragment 名詞前面加上三個句點:
query { Lift(id: "jazz-cat") { ...liftInfo trailAccess { ...trailInfo } } Trail(id: "river-run") { ...trailInfo groomed trees night } }
fragment trailInfo on Trail { name difficulty accessedByLifts { ...liftInfo } }
fragment liftInfo on Lift { name status capacity night elevationGain }
在這個範例中,我們建立了一個稱為 trailInfo 的 fragment,並在 query 的兩個地方使用它。我們也在 trailInfo fragment 中使用 liftInfo fragment 來選擇與它連接的纜椅資料。你可以視需求建立任意數量的 fragment,並交換使用它們。在 River Run Trail query 使用的選擇組中,我們將 fragment 與想要選擇的、關於 River Run 雪道的其他資料結合。你可以一併使用 fragment 與選擇組的其他欄位,也可以在單個選擇組中結合多個屬於同樣型態的 fragment:
你可以使用 query (查詢)從 GraphQL API 請求資料。query 描述你想要從 GraphQL 伺服器取得的資料。當你傳送 query 時,就是以 field (欄位)為單位索取資料。這些欄位對應伺服器回傳的 JSON 資料回應內的同一組欄位。例如,如果你傳送一個索取 allLifts 的 query,並請求 name 與 status 欄位,就會收到一個含有 allLifts 陣列與每一個纜椅的 name 與 status 的字串。
using System; using Oracle.ManagedDataAccess.Client; using System.IO; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration.Json;
我們可以在設定連接字符串中直接設定連接池(connection pool)。選項 Pooling 設置為 false,會禁用連接池; 預設是啟用的: Pooling=true。 Min Pool Size 和 Max Pool Size 允許配置池中的連接數。預設情況下,Min Pool Size 的值為 1,Max Pool Size 的值為 100。Connection Lifetime 定義了連線在釋放前在池中保持不活躍狀態的時間。
using System; using Oracle.ManagedDataAccess.Client; using System.IO; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration.Json;
namespaceOracleSample.src { publicclassCommandSample { publicstaticvoidCreateCommand() { using (var connection = new OracleConnection(GetConnectionString())) { string sql = "SELECT empno, ename, hiredate, sal, deptno From emp"; var command = new OracleCommand(sql, connection); connection.Open(); //... } } privatestaticstringGetConnectionString() { var configurationBuilder = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("config.json"); IConfiguration config = configurationBuilder.Build(); string connectionString = config["Data:DefaultConnection:ConnectionString"]; return connectionString; } } }
using System; using System.IO; using Oracle.ManagedDataAccess.Client; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration.Json;
namespaceOracleSample.src { publicclassExecuteSample { publicstaticvoidExecuteReader(int deptnoParameter) { string sql = "SELECT empno, ename, hiredate, sal, comm, deptno From emp where deptno = :deptno order by empno";
try { using (var connection = new OracleConnection(GetConnectionString())) using (var command = new OracleCommand(sql, connection)) { command.BindByName = true;
OracleParameter deptnoBind = new OracleParameter("deptno", OracleDbType.Int32); deptnoBind.Value = deptnoParameter; command.Parameters.Add(deptnoBind);
connection.Open(); using (var reader = command.ExecuteReader()) { while (reader.Read()) { short empno = reader.GetInt16(0); string ename = reader.GetString(1); DateTime hiredate = reader.GetDateTime(2); float sal = reader.GetFloat(3); float? comm = reader.IsDBNull(4) ? (float?)null : reader.GetFloat(4); short deptno = reader.GetInt16(5);
short empno = (short)reader[0]; string ename = (string)reader[1]; DateTime hiredate = (DateTime)reader[2]; float sal = (float)reader[3]; float? comm = reader.IsDBNull(4) ? (float?) null : (float?)reader[4]; short deptno = (short)reader[5];
OracleDataReader 的索引器還允許使用 string 而不是 int 傳遞列名 (column name)。在這些不同的選項中,這是最慢的方法,但它的可讀性最佳,與發出服務調用所需的時間相比,訪問索引器所需的額外時間其實可以忽略不計。
src/ExecuteSample.cs
1 2 3 4 5 6
short empno = (short)reader["empno"]; string ename = (string)reader["ename"]; DateTime hiredate = (DateTime)reader["hiredate"]; float sal = (float)reader["sal"]; float? comm = reader.IsDBNull(4) ? (float?)null : (float?)reader["comm"]; short deptno = (short)reader["deptno"];
強烈型的語言有時在映對資料庫的資料型態實在是很困擾,既然是從資料庫返回的資料,不管它是否為 null,總是會有初始值,我們就直接使用 var 類型推斷。 要記得使用 var 類型推斷,一定要賦予初始值,否則它無法推斷:
src/ExecuteSample.cs
1 2 3 4 5 6
var empno = reader["empno"]; var ename = reader["ename"]; var hiredate = reader["hiredate"]; var sal = reader["sal"]; var comm = reader["comm"]; var deptno = reader["deptno"];
try { using (var connection = new OracleConnection(GetConnectionString())) using (var command = new OracleCommand(sql, connection)) { command.BindByName = true;
OracleParameter empnoBind = new OracleParameter("empno", OracleDbType.Int32); empnoBind.Value = newEmployee.empno; command.Parameters.Add(empnoBind);
OracleParameter enameBind = new OracleParameter("ename", OracleDbType.Varchar2); enameBind.Value = newEmployee.ename; command.Parameters.Add(enameBind);
OracleParameter jobBind = new OracleParameter("job", OracleDbType.Varchar2); jobBind.Value = newEmployee.job; command.Parameters.Add(jobBind);
OracleParameter mgrBind = new OracleParameter("mgr", OracleDbType.Int32); mgrBind.Value = newEmployee.mgr; command.Parameters.Add(mgrBind);
OracleParameter hiredateBind = new OracleParameter("hiredate", OracleDbType.Date); hiredateBind.Value = newEmployee.hiredate; command.Parameters.Add(hiredateBind);
OracleParameter salBind = new OracleParameter("sal", OracleDbType.Decimal); salBind.Value = newEmployee.sal; command.Parameters.Add(salBind);
OracleParameter commBind = new OracleParameter("comm", OracleDbType.Decimal); commBind.Value = newEmployee.comm; command.Parameters.Add(commBind);
OracleParameter deptnoBind = new OracleParameter("deptno", OracleDbType.Int32); deptnoBind.Value = newEmployee.deptno; command.Parameters.Add(deptnoBind);
using System; using System.IO; using Oracle.ManagedDataAccess.Client; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration.Json;
namespaceReceive.Services { publicclassOraDemoMessage { publicstaticvoidSave(string messageParameter, string createdbyParameter) { string sql = "INSERT INTO DEMO_MESSAGES (message, createdby) " + "VALUES (:message, :createdby)"; try { using (var connection = new OracleConnection(GetConnectionString())) using (var command = new OracleCommand(sql, connection)) { command.BindByName = true;
OracleParameter messageBind = new OracleParameter("message", OracleDbType.Varchar2); messageBind.Value = messageParameter; command.Parameters.Add(messageBind);
OracleParameter createdbyBind = new OracleParameter("createdby", OracleDbType.Varchar2); createdbyBind.Value = createdbyParameter; command.Parameters.Add(createdbyBind);