程序員的重復勞動陷阱

程序員的重復勞動陷阱

作者: ChaosYang1987 來源: 博客園 發布時間: 2019-12-15 15:17 閱讀: 3449 次 推薦: 74 原文鏈接 [收藏]

  同樣是一樣的計算機專業畢業,進入職場的職位和工作都差不多,為何有些程序員短短幾年就成長為全能選手或領域專家,有些程序員還在做CRUD?

  程序員的重復勞動陷阱

  不知道大家有沒有這樣的感覺,每次加入一個新的公司/組,一開始總是要學這個學那個,可能會花很多時間看現有的代碼,然后花一些時間實現一點點小的功能,等到經過一段時間后,自己對工作越來越得心應手,提來的類似需求馬上就可以做,以做得多做得快為驕傲,覺的這樣可以更受老板青睞,可以升職加薪。

  我在畢業第三年的時候加入前公司,在加入公司的第一個季度,我主要再做一些邊緣工具以及理解系統,從第二個季度開始在組里的核心業務上開發。當時自己為了能夠快速的出成果,會從組里所有的任務里挑看著比較容易實現的做,往往一天就可以做完一個或者兩個任務。做完一個任務后,發現backlog里面有相似的任務,我也“趕緊”搶過來assign給自己,然后快速的做完,提交code review。從那個季度開始我每個季度做的工單越來越多,超過組里的所有其他成員,自己也對自己的“高效”洋洋得意,覺的自己工作的非常充實,進步很大。

  然而在這個過程中,我已經不知不覺得掉到“重復勞動”的陷阱中去了。

  我們在寫代碼的時候,有一個原則交叫DRY(Don’t Repeat Youself)原則,簡單通俗的說就是不要copy paste代碼,能抽象成函數的抽象成函數,能抽象成基類的抽象成基類。但是程序員的工作本身也應該遵循一樣的道理,那就是盡量不要做重復的工作。

  重復勞動對程序員的危害

  回到開篇的問題,同樣是一樣的計算機專業畢業,進入職場的職位和工作都差不多,為何有些程序員短短幾年就成長為全能選手或領域專家,有些程序員還在做CRUD?

  大部分的技術學習曲線類似于上圖,經歷過短暫的入門期和相對長一些的積累期之后,可能大部分技術都會進入到高效期。在入門期和積累期的時候可能技能使用的效率會低一些,進入到高效期之后,隨著技能使用的效率大大提高,工作所產生的“輸出”也越來越大。因此“高效期“給人以充實的假象。

  一旦自己的某項技術進入到高效期,在此基礎上的提升會非常困難,可能之前工作三個月所掌握的新知識,比之后一年在工作中積累的要多。有時候我們看一個程序員工作了5年,但是他可能第一年學習并熟悉所用的技術,接下來4年都在做相同的工作,解決類似的需求,那么他的5年工作經驗等于1年乘以5。

  而有些程序員,他每工作一段時間之后,都會鉆研技術更深的部分,或者去學習新的技術,總是保持著在嘗試自己并不擅長的領域,那么這樣的程序員,他的5年工作經驗會比前一種程序員要多。

  如何擺脫重復勞動的循環

  既然重復勞動的危害這么大,那么我們是否可以擺脫重復勞動的循環呢?

  有的時候,程序員自己也不想老是重復的干類似的東西,但是無奈被派發的任務重復的很多,似乎自己可以選擇的不多。

  在我自己在第三年大量重復勞動之后,我的經理找到我談話,說我不應該這樣重復自己,同樣的事情做一兩次就好了,再重復的做對自己的幫助不大。我分享一下我是怎么樣避免重復的勞動的:

  1. 找到Pattern,解決一類問題而不是一個問題。當你解決了N次類似的需求的時候,是否可以把這些問題抽象出來,是否可以去自動化的實現這類需求?改了N次bug之后,是否可以發現bug的規律,能夠開發出靜態分析工具來抓住這些bug?
  2. 嘗試用新的技術解決同樣的問題。有時當項目的實現并沒有多少規定的時候,我們可以在一定的自由度下嘗試新的工具。今年年初的時候我去嘗試修改一個已有的內部工具前段,持著學習新技術的心理,我用Redux重新實現了前段,而不是在原有的jQuery的前段基礎上修改。
  3. 嘗試換崗。換崗位可以直接的讓你接受不同的項目,做一些不同的事情。我在上家公司的第一組待了近三年才換組,現在來看應該更早的時候嘗試不同的事情。換崗位也會帶來一些其他的問題,比如到新崗位之后可能會影響晉升速度,需要重新建立自己的權威等等。
  4. 換工作。換工作是一個終極大招,它會帶來很多其他的變化,不建議只是為了脫離重復勞動而換工作。如果沒有養成良好的學習習慣,那么換一份新工作之后也很有可能陷入到新的重復勞動的循環中。

  重復勞動不可以完全避免

  重復勞動是否可以完全避免呢?

  我覺的是不可以避免的。以上的內容都是基于程序員成長的角度去分析問題,重復勞動是有害的。但是將程序員的勞動視為價值輸出的話,熟練的價值輸出確實也是程序員的價值之一,可以爭取到更高的薪酬。

  我們站在組織的角度上來看,重復的需求永遠存在,這些重復的需求需要被完成。如果在人員配置有限的情況下,不可避免的單個個體成員需要去進行一定的重復勞動。而由于時間上的緊迫性,可能必須要用高效粗暴的方法來實現。

  如果你是公司的初創成員,需要在初期做大量的重復工作來從無到有的實現新的產品,那毫無疑問這是應該做的,因為這樣的重復勞動帶來的收益可能是巨大的。

  希望大家在工作中都可以正確的認識到重復勞動的陷阱,讓自己能夠保持持久的成長。

74
3

請先登錄 提交中…

標簽:程序員 重復勞動

文章列表

從零開始入門 K8s | 手把手帶你理解 etcd

從零開始入門 K8s | 手把手帶你理解 etcd

作者: 阿里巴巴云原生 來源: 博客園 發布時間: 2020-01-13 11:16 閱讀: 1201 次 推薦: 3 原文鏈接 [收藏]

  作者 | 曾凡松(逐靈) 阿里云容器平臺高級技術專家

  本文整理自《CNCF x Alibaba 云原生技術公開課》第 16 講。

導讀:etcd 是用于共享配置和服務發現的分布式、一致性的 KV 存儲系統。本文從 etcd 項目發展所經歷的幾個重要時刻開始,為大家介紹了 etcd 的總體架構及其設計中的基本原理。希望能夠幫助大家更好的理解和使用 etcd。

  一、etcd 項目的發展歷程

  etcd 誕生于 CoreOS 公司,它最初是用于解決集群管理系統中 OS 升級的分布式并發控制以及配置文件的存儲與分發等問題。基于此,etcd 被設計為提供高可用、強一致的小型 keyvalue 數據存儲服務。

  項目當前隸屬于 CNCF 基金會,被 AWS、Google、Microsoft、Alibaba 等大型互聯網公司廣泛使用。

1.png

  最初,在 2013 年 6 月份由 CoreOS 公司向 GitHub 中提交了第一個版本的初始代碼。

  到了 2014 年的 6 月,社區發生了一件事情,Kubernetes v0.4 版本發布。這里有必要介紹一下 Kubernetes 項目,它首先是一個容器管理平臺,由谷歌開發并貢獻給社區,因為它集齊了谷歌在容器調度以及集群管理等領域的多年經驗,從誕生之初就備受矚目。在 Kubernetes v0.4 版本中,它使用了 etcd 0.2 版本作為實驗核心元數據的存儲服務,自此 etcd 社區得到了飛速的發展。

  很快,在 2015 年 2 月份,etcd 發布了第一個正式的穩定版本 2.0。在 2.0 版本中,etcd 重新設計了 Raft 一致性算法,并為用戶提供了一個簡單的樹形數據視圖,在 2.0 版本中 etcd 支持每秒超過 1000 次的寫入性能,滿足了當時絕大多數的應用場景需求。2.0 版本發布之后,經過不斷的迭代與改進,其原有的數據存儲方案逐漸成為了新時期的性能瓶頸,之后 etcd 啟動了 v3 版本的方案設計。

  2017 年 1 月份的時候,etcd 發布了 3.1 版本,v3 版本方案基本上標志著 etcd 技術上全面成熟。在 v3 版本中 etcd 提供了一套全新的 API,重新實現了更高效的一致性讀取方法,并且提供了一個 gRPC 的 proxy 用于擴展 etcd 的讀取性能。同時,在 v3 版本的方案中包含了大量的 GC 優化,在性能優化方面取得了長足的進步,在該版本中 etcd 可以支持每秒超過 10000 次的寫入。

  2018 年,CNCF 基金會下的眾多項目都使用了 etcd 作為其核心的數據存儲。據不完全統計,使用 etcd 的項目超過了 30 個,在同年 11 月份,etcd 項目自身也成為了 CNCF 旗下的孵化項目。進入 CNCF 基金會后,etcd 擁有了超過 400 個貢獻組,其中包含了來自 AWS、Google、Alibaba 等 8 個公司的 9 個項目維護者。

  2019 年,etcd 即將發布全新的 3.4 版本,該版本由 Google、Alibaba 等公司聯合打造,將進一步改進 etcd 的性能及穩定性,以滿足在超大型公司使用中苛刻的場景要求。

  二、架構及內部機制解析

  總體架構

  etcd 是一個分布式的、可靠的 key-value 存儲系統,它用于存儲分布式系統中的關鍵數據,這個定義非常重要。

2.png

  一個 etcd 集群,通常會由 3 個或者 5 個節點組成,多個節點之間通過 Raft 一致性算法的完成分布式一致性協同,算法會選舉出一個主節點作為 leader,由 leader 負責數據的同步與數據的分發。當 leader 出現故障后系統會自動地選取另一個節點成為 leader,并重新完成數據的同步。客戶端在多個節點中,僅需要選擇其中的任意一個就可以完成數據的讀寫,內部的狀態及數據協同由 etcd 自身完成。

  在 etcd 整個架構中,有一個非常關鍵的概念叫做 quorum,quorum 的定義是 (n+1)/2,也就是說超過集群中半數節點組成的一個團體,在 3 個節點的集群中,etcd 可以容許 1 個節點故障,也就是只要有任何 2 個節點可用,etcd 就可以繼續提供服務。同理,在 5 個節點的集群中,只要有任何 3 個節點可用,etcd 就可以繼續提供服務,這也是 etcd 集群高可用的關鍵。

  在允許部分節點故障之后繼續提供服務,就需要解決一個非常復雜的問題:分布式一致性。在 etcd 中,該分布式一致性算法由 Raft 一致性算法完成,這個算法本身是比較復雜的有機會再詳細展開,這里僅做一個簡單的介紹以方便大家對其有一個基本的認知。Raft 一致性算法能夠工作的一個關鍵點是:任意兩個 quorum 的成員之間一定會有一個交集(公共成員),也就是說只要有任意一個 quorum 存活,其中一定存在某一個節點(公共成員),它包含著集群中所有的被確認提交的數據。正是基于這一原理,Raft 一致性算法設計了一套數據同步機制,在 Leader 任期切換后能夠重新同步上一個 quorum 被提交的所有數據,從而保證整個集群狀態向前推進的過程中保持數據的一致。

3.png

  etcd 內部的機制比較復雜,但 etcd 給客戶提供的接口是簡單直接的。如上圖所示,我們可以通過 etcd 提供的客戶端去訪問集群的數據,也可以直接通過 http 的方式(類似 curl 命令)直接訪問 etcd。在 etcd 內部,其數據表示也是比較簡單的,我們可以直接把 etcd 的數據存儲理解為一個有序的 map,它存儲著 key-value 數據。同時 etcd 為了方便客戶端去訂閱數據的變更,也支持了一個 watch 機制,通過 watch 實時地拿到 etcd 中數據的增量更新,從而實現與 etcd 中的數據同步等業務邏輯。

  API 介紹

  接下來我們看一下 etcd 提供的接口,這里將 etcd 的接口分為了 5 組:

4.png

  • 第一組是 Put 與 Delete。上圖可以看到 put 與 delete 的操作都非常簡單,只需要提供一個 key 和一個 value,就可以向集群中寫入數據了,刪除數據的時候只需要指定 key 即可;
  • 第二組是查詢操作。etcd 支持兩種類型的查詢:第一種是指定單個 key 的查詢,第二種是指定的一個 key 的范圍;
  • 第三組是數據訂閱。etcd 提供了 Watch 機制,我們可以利用 watch 實時訂閱到 etcd 中增量的數據更新,watch 支持指定單個 key,也可以指定一個 key 的前綴,在實際應用場景中的通常會采用第二種形勢;
  • 第四組事務操作。etcd 提供了一個簡單的事務支持,用戶可以通過指定一組條件滿足時執行某些動作,當條件不成立的時候執行另一組操作,類似于代碼中的 if else 語句,etcd 確保整個操作的原子性;
  • 第五組是 Leases 接口。Leases 接口是分布式系統中常用的一種設計模式,其用法后面會具體展開。

  數據版本機制

  要正確使用 etcd 的 API,必須要知道內部對應數據版本號的基本原理。

  首先 etcd 中有個 term 的概念,代表的是整個集群 Leader 的任期。當集群發生 Leader 切換,term 的值就會 +1。在節點故障,或者 Leader 節點網絡出現問題,再或者是將整個集群停止后再次拉起,都會發生 Leader 的切換。

  第二個版本號叫做 revision,revision 代表的是全局數據的版本。當數據發生變更,包括創建、修改、刪除,其 revision 對應的都會 +1。特別的,在集群中跨 Leader 任期之間,revision 都會保持全局單調遞增。正是 revision 的這一特性,使得集群中任意一次的修改都對應著一個唯一的 revision,因此我們可以通過 revision 來支持數據的 MVCC,也可以支持數據的 Watch。

  對于每一個 KeyValue 數據節點,etcd 中都記錄了三個版本:

  • 第一個版本叫做 create_revision,是 KeyValue 在創建時對應的 revision;
  • 第二個叫做 mod_revision,是其數據被操作的時候對應的 revision;
  • 第三個 version 就是一個計數器,代表了 KeyValue 被修改了多少次。

  這里可以用圖的方式給大家展示一下:

5.png

  在同一個 Leader 任期之內,我們發現所有的修改操作,其對應的 term 值始終都等于 2,而 revision 則保持單調遞增。當重啟集群之后,我們會發現所有的修改操作對應的 term 值都變成了 3。在新的 Leader 任期內,所有的 term 值都等于3,且不會發生變化,而對應的 revision 值同樣保持單調遞增。從一個更大的維度去看,可以發現在 term=2 和 term=3 的兩個 Leader 任期之間,數據對應的 revision 值依舊保持了全局單調遞增。

  mvcc & streaming watch

  了解 etcd 的版本號控制后,接下來如何使用 etcd 多版本號來實現并發控制以及數據訂閱(Watch)。

  在 etcd 中支持對同一個 Key 發起多次數據修改,每次數據修改都對應一個版本號。etcd 在實現上記錄了每一次修改對應的數據,也就就意味著一個 key 在 etcd 中存在多個歷史版本。在查詢數據的時候如果不指定版本號,etcd 會返回 Key 對應的最新版本,當然 etcd 也支持指定一個版本號來查詢歷史數據。

6.png

  因為 etcd 將每一次修改都記錄了下來,使用 watch 訂閱數據時,可以支持從任意歷史時刻(指定 revision)開始創建一個 watcher,在客戶端與 etcd 之間建立一個數據管道,etcd 會推送從指定 revision 開始的所有數據變更。etcd 提供的 watch 機制保證,該 Key 的數據后續的被修改之后,通過這個數據管道即時的推送給客戶端。

  如下圖所示,etcd 中所有的數據都存儲在一個 b+tree 中(灰色),該 b+tree 保存在磁盤中,并通過 mmap 的方式映射到內存用來支持快速的訪問。灰色的 b+tree 中維護著 revision 到 value 的映射關系,支持通過 revision 查詢對應的數據。因為 revision 是單調遞增的,當我們通過 watch 來訂閱指定 revision 之后的數據時,僅需要訂閱該 b+ tree 的數據變化即可。

7.png

  在 etcd 內部還維護著另外一個 btree(藍色),它管理著 key 到 revision 的映射關系。當客戶端使用 key 查詢數據時,首先需要經過藍色的 btree 將 key 轉化為對應的 revision,再通過灰色的 btree 查詢到對應的數據。

  細心的讀者會發現,etcd 將每一次修改都記錄下來會導致數據持續增長,這會帶來內存及磁盤的空間消耗,同時也會影響 b+tree 的查詢效率。為了解決這一問題,在 etcd 中會運行一個周期性的 Compaction 的機制來清理歷史數據,將一段時間之前的同一個 Key 的多個歷史版本數據清理掉。最終的結果是灰色的 b+tree 依舊保持單調遞增,但可能會出現一些空洞。

  mini-transactions

  在理解了 mvcc 機制及 watch 機制之后,繼續看 etcd 提供的 mini-transactions 機制。etcd 的 transaction 機制比較簡單,基本可以理解為一段 if-else 程序,在 if 中可以提供多個操作,如下圖所示:

8.png

  If 里面寫了兩個條件,當 Value(key1) 大于 “bar" 并且 Version(key1) 的版本等于 2 的時候,執行 Then 里面指定的操作:修改 Key2 的數據為 valueX,同時刪除 Key3 的數據。如果不滿足條件,則執行另外一個操作:Key2 修改為 valueY。

  在 etcd 內部會保證整個事務操作的原子性。也就是說 If 操作所有的比較條件,其看到的視圖一定是一致的。同時它能夠確保多個操作的原子性不會出現 Then 中的操作僅執行了一半的情況。

  通過 etcd 提供的事務操作,我們可以在多個競爭中去保證數據讀寫的一致性,比如說前面已經提到過的 Kubernetes 項目,它正是利用了 etcd 的事務機制,來實現多個 KubernetesAPI server 對同樣一個數據修改的一致性。

  lease 的概念及用法

  lease 是分布式系統中一個常見的概念,用于代表一個分布式租約。典型情況下,在分布式系統中需要去檢測一個節點是否存活的時,就需要租約機制。

9.png

  上圖示例中的代碼示例首先創建了一個 10s 的租約,如果創建租約后不做任何的操作,那么 10s 之后,這個租約就會自動過期。接著將 key1 和 key2 兩個 key value 綁定到這個租約之上,這樣當租約過期時 etcd 就會自動清理掉 key1 和 key2,使得節點 key1 和 key2 具備了超時自動刪除的能力。

  如果希望這個租約永不過期,需要周期性的調用 KeeyAlive 方法刷新租約。比如說需要檢測分布式系統中一個進程是否存活,可以在進程中去創建一個租約,并在該進程中周期性的調用 KeepAlive 的方法。如果一切正常,該節點的租約會一致保持,如果這個進程掛掉了,最終這個租約就會自動過期。

  在 etcd 中,允許將多個 key 關聯在同一個 lease 之上,這個設計是非常巧妙的,可以大幅減少 lease 對象刷新帶來的開銷。試想一下,如果有大量的 key 都需要支持類似的租約機制,每一個 key 都需要獨立的去刷新租約,這會給 etcd 帶來非常大的壓力。通過多個 key 綁定在同一個 lease 的模式,我們可以將超時間相似的 key 聚合在一起,從而大幅減小租約刷新的開銷,在不失靈活性同時能夠大幅提高 etcd 支持的使用規模。

  三、典型的使用場景介紹

  元數據存儲

  Kubernetes 將自身所用的狀態存儲在 etcd 中,其狀態數據的高可用交給 etcd 來解決,Kubernetes 系統自身不需要再應對復雜的分布式系統狀態處理,自身的系統架構得到了大幅的簡化。

10.png

  Server Discovery (Naming Service)

  第二個場景是 Service Discovery,也叫做名字服務。在分布式系統中,通常會出現的一個模式就是需要多個后端(可能是成百上千個進程)來提供一組對等的服務,比如說檢索服務、推薦服務。

11.png

  對于這樣一種后端服務,通常情況下為了簡化后端服務的運維成本(節點故障時隨時被替換),后端的這一進程會被類似 Kubernetes 這樣的集群管理系統所調度,這樣當用戶(或上游服務)調用過來時,我們就需要一個服務發現機制來解決服務路由問題。這一服務發現問題可以利用 etcd 來高效解決,方式如下:

  • 在進程內部啟動之后,可以將自身所在的地址注冊到 etcd;
  • API 網關夠通過 etcd 及時感知到后端進程的地址,當后端進程發生故障遷移時會重新注冊到 etcd 中,API 網關也能夠及時地感知到新的地址;
  • 利用 etcd 提供的 Lease 機制,如果提供服務的進程運行過程中出現了異常(crash),API 網關也可以摘除其流量避免調用超時。

  在這一架構中,服務狀態數據被 etcd 接管,API 網關本身也是無狀態的,可以水平地擴展來服務更多的客戶。同時得益于 etcd 的良好性能,可以支持上萬個后端進程的節點,使得這一架構可以服務于大型的企業。

  Distributed Coordination: leader election

  在分布式系統中,有一種典型的設計模式就是 Master+Slave。通常情況下,Slave 提供了 CPU、內存、磁盤以及網絡等各種資源 ,而 Master 用來調和這些節點以使其對外提供一個服務(比如分布式存儲,分布式計算)。典型的分布式存儲服務(HDFS)以及分布式計算服務(Hadoop)它們都是采用了類似這樣的設計模式。這樣的設計模式會有一個典型的問題:Master 節點的可用性。當 Master 故障以后,整個集群的服務就掛掉了,沒有辦法再服務用戶的請求。

  為了解決這個問題,典型的做法就是啟動多個 Master 節點。因為 Master 節點內會包含控制邏輯,多個節點之間的狀態同步是非常復雜的,這里最典型的做法就是通過選主的方式,選出其中一個節點作為主節點來提供服務,另一個節點處于等待狀態。

12.png

  通過 etcd 提供的機制可以很容易的實現分布式進程的選主功能,比如可以通過對同一個 key 的事務寫來實現搶主的邏輯。一般而言,被選主的 Leader 會將自己的 IP 注冊到 etcd 中,使得 Slave 節點能夠及時獲取到當前的 Leader 地址,從而使得系統按照之前單個 Master 節點的方式繼續工作。當 Leader 節點發生異常之后,通過 etcd 能夠選取出一個新的節點成為主節點,并且注冊新的 IP 之后,Slave 又能夠拉取新的主節點的 IP,繼續恢復服務。

  Distributed Coordination 分布式系統并發控制

  在分布式系統中,當我們去執行一些任務,比如說去升級 OS、或者說升級 OS 上的軟件的時候、又或者去執行一些計算任務的時候,出于對后端服務的瓶頸或者是業務穩定性的考慮,通常情況下需要控制任務的并發度。如果該任務缺少一個調和的 Master 節點,可以通過 etcd 來完成這樣的分布式系統工作。

13.png

  在這個模式中通過 etcd 去實現一個分布式的信號量,并且可以利用 etcd leases 機制來實現自動地剔除掉故障節點。在進程執行過程中,如果進程的運行周期比較長,我們可以將進程運行過程中的一些狀態數據存儲到 etcd,從而使得當進程故障之后且需要恢復到其他地方時,能夠從 etcd 中去恢復一些執行狀態,而不需要重新去完成整個的計算邏輯,以此來加速整個任務的執行效率。

  本文總結

  本文分享的主要內容就到此為止了,這里為大家簡單總結一下:

  • 第一部分,為大家介紹了 etcd 項目是如何誕生的,以及在 etcd 發展過程中經歷的幾個重要時刻;
  • 第二部分,為大家介紹了 etcd 的架構以及其內部的基本操作接口,在理解 etcd 是如何實現高可用的基礎之上,展示了 etcd 數據的一些基本操作以及其內部的實現原理;
  • 第三部分,介紹了三種典型的 etcd 使用場景,以及在對應的場景下,分布式系統的設計思路。

3
0

請先登錄 提交中…

標簽:kubernetes etcd

文章列表

LINQ to SQL語句(20)之存儲過程

LINQ to SQL語句(20)之存儲過程

作者: 李永京 來源: 博客園 發布時間: 2008-09-18 17:23 閱讀: 13068 次 推薦: 0 原文鏈接 [收藏]

摘要:這個系列的第二十篇,講解存儲過程用法。
[1] 標量返回和單一結果集
[2] 多個可能形狀的單一結果集
[3] 多個結果集
[4] 帶輸出參數

系列文章導航:

LINQ to SQL語句(1)之Where

LINQ to SQL語句(2)之Select/Distinct

LINQ to SQL語句(3)之Count/Sum/Min/Max/Avg

LINQ to SQL語句(4)之Join

LINQ to SQL語句(5)之Order By

LINQ to SQL語句(6)之Group By/Having

LINQ to SQL語句(7)之Exists/In/Any/All/Contains

LINQ to SQL語句(8)之Concat/Union/Intersect/Except

LINQ to SQL語句(9)之Top/Bottom和Paging和SqlMethods

LINQ to SQL語句(10)之Insert

LINQ to SQL語句(11)之Update

LINQ to SQL語句(12)之Delete和使用Attach

LINQ to SQL語句(13)之開放式并發控制和事務

LINQ to SQL語句(14)之Null語義和DateTime

LINQ to SQL語句(15)之String

LINQ to SQL語句(16)之對象標識

LINQ to SQL語句(17)之對象加載

LINQ to SQL語句(18)之運算符轉換

LINQ to SQL語句(19)之ADO.NET與LINQ to SQL

LINQ to SQL語句(20)之存儲過程

LINQ to SQL語句(21)之用戶定義函數

LINQ to SQL語句(22)之DataContext

LINQ to SQL語句(23)之動態查詢

LINQ to SQL語句(24)之視圖

LINQ to SQL語句(25)之繼承

LINQ簡介

adsfsaf

存儲過程

在我們編寫程序中,往往需要一些存儲過程,在LINQ to SQL中怎么使用呢?也許比原來的更簡單些。下面我們以NORTHWND.MDF數據庫中自帶的幾個存儲過程來理解一下。

1.標量返回

在數據庫中,有名為Customers Count By Region的存儲過程。該存儲過程返回顧客所在"WA"區域的數量。

ALTER PROCEDURE [dbo].[NonRowset] (@param1 NVARCHAR(15)) AS BEGIN SET NOCOUNT ON; DECLARE @count int SELECT @count = COUNT(*)FROM Customers WHERECustomers.Region = @Param1 RETURN @count END

我們只要把這個存儲過程拖到O/R設計器內,它自動生成了以下代碼段:

[Function(Name = "dbo.[Customers Count By Region]")] public int Customers_Count_By_Region([Parameter
(DbType = "NVarChar(15)")] string param1) { IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), param1); return ((int)(result.ReturnValue)); }

我們需要時,直接調用就可以了,例如:

int count = db.CustomersCountByRegion("WA"); Console.WriteLine(count);

語句描述:這個實例使用存儲過程返回在“WA”地區的客戶數。

2.單一結果集

從數據庫中返回行集合,并包含用于篩選結果的輸入參數。 當我們執行返回行集合的存儲過程時,會用到結果類,它存儲從存儲過程中返回的結果。

下面的示例表示一個存儲過程,該存儲過程返回客戶行并使用輸入參數來僅返回將“London”列為客戶城市的那些行的固定幾列。

ALTER PROCEDURE [dbo].[Customers By City]

LINQ to SQL語句(23)之動態查詢

LINQ to SQL語句(23)之動態查詢

作者: 李永京 來源: 博客園 發布時間: 2008-09-18 18:34 閱讀: 18448 次 推薦: 2 原文鏈接 [收藏]

摘要:這個系列的第二十三篇,講解動態查詢。
[1] Select與Where
[2] OrderBy與Union

系列文章導航:

LINQ to SQL語句(1)之Where

LINQ to SQL語句(2)之Select/Distinct

LINQ to SQL語句(3)之Count/Sum/Min/Max/Avg

LINQ to SQL語句(4)之Join

LINQ to SQL語句(5)之Order By

LINQ to SQL語句(6)之Group By/Having

LINQ to SQL語句(7)之Exists/In/Any/All/Contains

LINQ to SQL語句(8)之Concat/Union/Intersect/Except

LINQ to SQL語句(9)之Top/Bottom和Paging和SqlMethods

LINQ to SQL語句(10)之Insert

LINQ to SQL語句(11)之Update

LINQ to SQL語句(12)之Delete和使用Attach

LINQ to SQL語句(13)之開放式并發控制和事務

LINQ to SQL語句(14)之Null語義和DateTime

LINQ to SQL語句(15)之String

LINQ to SQL語句(16)之對象標識

LINQ to SQL語句(17)之對象加載

LINQ to SQL語句(18)之運算符轉換

LINQ to SQL語句(19)之ADO.NET與LINQ to SQL

LINQ to SQL語句(20)之存儲過程

LINQ to SQL語句(21)之用戶定義函數

LINQ to SQL語句(22)之DataContext

LINQ to SQL語句(23)之動態查詢

LINQ to SQL語句(24)之視圖

LINQ to SQL語句(25)之繼承

LINQ簡介

adsfsaf

動態查詢

有這樣一個場景:應用程序可能會提供一個用戶界面,用戶可以使用該用戶界面指定一個或多個謂詞來篩選數據。這種情況在編譯時不知道查詢的細節,動態查詢將十分有用。

在LINQ中,Lambda表達式是許多標準查詢運算符的基礎,編譯器創建lambda表達式以捕獲基礎查詢方法(例如 Where、Select、Order By、Take While 以及其他方法)中定義的計算。表達式目錄樹用于針對數據源的結構化查詢,這些數據源實現IQueryable<T>。例如,LINQ to SQL 提供程序實現 IQueryable<T>接口,用于查詢關系數據存儲。C#和Visual Basic編譯器會針對此類數據源的查詢編譯為代碼,該代碼在運行時將生成一個表達式目錄樹。然后,查詢提供程序可以遍歷表達式目錄樹數據結構,并將其轉換為適合于數據源的查詢語言。

表達式目錄樹在LINQ中用于表示分配給類型為Expression<TDelegate>的變量的Lambda表達式。還可用于創建動態LINQ查詢。

System.Linq.Expressions命名空間提供用于手動生成表達式目錄樹的API。Expression類包含創建特定類型的表達式目錄樹節點的靜態工廠方法,例如,ParameterExpression(表示一個已命名的參數表達式)或 MethodCallExpression(表示一個方法調用)。編譯器生成的表達式目錄樹的根始終在類型Expression<TDelegate>的節點中,其中TDelegate是包含至多五個輸入參數的任何TDelegate委托;也就是說,其根節點是表示一個lambda表達式。

下面幾個例子描述如何使用表達式目錄樹來創建動態LINQ查詢。

1.Select

下面例子說明如何使用表達式樹依據 IQueryable 數據源構造一個動態查詢,查詢出每個顧客的ContactName,并用GetCommand方法獲取其生成SQL語句。

//依據IQueryable數據源構造一個查詢 IQueryable<Customer> custs = db.Customers; //組建一個表達式樹來創建一個參數 ParameterExpression param = Expression.Parameter(typeof(Customer), "c"); //組建表達式樹:c.ContactName Expression selector = Expression.Property(param, typeof(Customer).GetProperty("ContactName")); Expression pred = Expression.Lambda(selector, param); //組建表達式樹:Select(c=>c.ContactName) Expression expr = Expression.Call(typeof(Queryable), "Select", new Type[] { typeof(Customer), typeof(string) }, Expression.Constant(custs), pred); //使用表達式樹來生成動態查詢 IQueryable<string> query = db.Customers.AsQueryable() .Provider.CreateQuery<string>(expr); //使用GetCommand方法獲取SQL語句 System.Data.Common.DbCommand cmd = db.GetCommand(query); Console.WriteLine(cmd.CommandText);

生成的SQL語句為:

SELECT [t0].[ContactName] FROM [dbo].[Customers] AS [t0]

2.Where

下面一個例子是“搭建”Where用法來動態查詢城市在倫敦的顧客。

IQueryable<Customer> custs = db.Customers; //創建一個參數c ParameterExpression param = Expression.Parameter(typeof(Customer), "c"); //c.City=="London" Expression left = Expression.Property(param, typeof(Customer).GetProperty("City")); Expression right = Expression.Constant("London"); Expression filter = Expression.Equal(left, right); Expression pred = Expression.Lambda(filter, param); //Where(c=>c.City=="London") Expression expr = Expression.Call(typeof(Queryable), "Where", new Type[] { typeof(Customer) }, Expression.Constant(custs), pred); //生成動態查詢 IQueryable<Customer> query = db.Customers.AsQueryable() .Provider.CreateQuery<Customer>(expr);

生成的SQL語句為:

SELECT [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].[Phone], [t0].[Fax] FROM [dbo].[Customers] AS [t0] WHERE [t0].[City] = @p0

LINQ to SQL語句(9)之Top/Bottom和Paging和SqlMethods

LINQ to SQL語句(9)之Top/Bottom和Paging和SqlMethods

作者: 李永京 來源: 博客園 發布時間: 2008-09-18 15:48 閱讀: 21134 次 推薦: 1 原文鏈接 [收藏]

摘要:這個系列的第九篇,講解Top/Bottom和Paging和SqlMethods操作符用法。
[1] Top/Bottom和Paging講解
[2] SqlMethods講解

系列文章導航:

LINQ to SQL語句(1)之Where

LINQ to SQL語句(2)之Select/Distinct

LINQ to SQL語句(3)之Count/Sum/Min/Max/Avg

LINQ to SQL語句(4)之Join

LINQ to SQL語句(5)之Order By

LINQ to SQL語句(6)之Group By/Having

LINQ to SQL語句(7)之Exists/In/Any/All/Contains

LINQ to SQL語句(8)之Concat/Union/Intersect/Except

LINQ to SQL語句(9)之Top/Bottom和Paging和SqlMethods

LINQ to SQL語句(10)之Insert

LINQ to SQL語句(11)之Update

LINQ to SQL語句(12)之Delete和使用Attach

LINQ to SQL語句(13)之開放式并發控制和事務

LINQ to SQL語句(14)之Null語義和DateTime

LINQ to SQL語句(15)之String

LINQ to SQL語句(16)之對象標識

LINQ to SQL語句(17)之對象加載

LINQ to SQL語句(18)之運算符轉換

LINQ to SQL語句(19)之ADO.NET與LINQ to SQL

LINQ to SQL語句(20)之存儲過程

LINQ to SQL語句(21)之用戶定義函數

LINQ to SQL語句(22)之DataContext

LINQ to SQL語句(23)之動態查詢

LINQ to SQL語句(24)之視圖

LINQ to SQL語句(25)之繼承

LINQ簡介

adsfsaf

Top/Bottom操作

適用場景:適量的取出自己想要的數據,不是全部取出,這樣性能有所加強。

Take

說明:獲取集合的前n個元素;延遲。即只返回限定數量的結果集。

var q = ( from e in db.Employees orderby e.HireDate select e) .Take(5);

語句描述:選擇所雇用的前5個雇員。

Skip

說明:跳過集合的前n個元素;延遲。即我們跳過給定的數目返回后面的結果集。

var q = ( from p in db.Products orderby p.UnitPrice descending select p) .Skip(10);

語句描述:選擇10種最貴產品之外的所有產品。

TakeWhile

說明:直到某一條件成立就停止獲取;延遲。即用其條件去依次判斷源序列中的元素,返回符合判斷條件的元素,該判斷操作將在返回false或源序列的末尾結束 。

SkipWhile

說明:直到某一條件成立就停止跳過;延遲。即用其條件去判斷源序列中的元素并且跳過第一個符合判斷條件的元素,一旦判斷返回false,接下來將不再進行判斷并返回剩下的所有元素。

Paging(分頁)操作

適用場景:結合Skip和Take就可實現對數據分頁操作。

1.索引

var q = ( from c in db.Customers orderby c.ContactName select c) .Skip(50) .Take(10);

語句描述:使用Skip和Take運算符進行分頁,跳過前50條記錄,然后返回接下來10條記錄,因此提供顯示Products表第6頁的數據。

2.按唯一鍵排序

var q = ( from p in db.Products where p.ProductID > 50 orderby p.ProductID select p) .Take(10);

語句描述:使用Where子句和Take運算符進行分頁,首先篩選得到僅50 (第5頁最后一個ProductID)以上的ProductID,然后按ProductID排序,最后取前10個結果,因此提供Products表第6頁的數據。請注意,此方法僅適用于按唯一鍵排序的情況。

繼續>>下一頁
[第1頁][第2頁]

1
0

請先登錄 提交中…

標簽:LINQ LINQ to SQL

文章列表

走進Linq-Linq to SQL How do I(1)

走進Linq-Linq to SQL How do I(1)

作者: 橫刀天笑 來源: 博客園 發布時間: 2008-09-23 18:57 閱讀: 14089 次 推薦: 2 原文鏈接 [收藏]

[1] 走進Linq-Linq to SQL How do I(1)
[2] 走進Linq-Linq to SQL How do I(1)
[3] 走進Linq-Linq to SQL How do I(1)
[4] 走進Linq-Linq to SQL How do I(1)
[5] 走進Linq-Linq to SQL How do I(1)

系列文章導航:

走進Linq–Linq橫空出世篇

走進Linq-輝煌的背后

走進Linq-Linq大觀園

不能不說的C#特性-對象集合初始化器

不能不說的C#特性-匿名類型與隱式類型局部變量

不能不說的C#特性-擴展方法

不能不說的C#特性-匿名方法和Lambda表達式

不能不說的C#特性-迭代器(上)及一些研究過程中的副產品

不能不說的C#特性-迭代器(下),yield以及流的延遲計算

走進Linq-Linq to Objects(上)基礎篇

走進Linq-Linq to Objects(下)實例篇

走進Linq-Linq to SQL感性認識篇

走進Linq-Linq to SQL How do I(1)

走進Linq-Linq to SQL How do I(2)

走進Linq-Linq to SQL How do I(3)

走進Linq-How do I(4)拾遺補零篇第一節

走進Linq-Linq to SQL源代碼賞析 Table的獲取過程

走進Linq-Linq to SQL源代碼賞析之Provider的初始化

走進Linq-Linq to SQL源代碼賞析,通過Linq to SQL看Linq

How Do I第一篇,難度系數50,定位為入門級。

上一篇對Linq to SQL做了一個大致的介紹,從這一篇起,將對要完成一項Linq to SQL的Case要做的一些事情,主要從細節上做一些講解。不會很深入,但是卻又是必須的。為了使講解不落于泛泛而談,我們首先來構建實例:

還是以博客園的系統為例子,既然稱Linq to SQL為一個ORM框架,ORM,對象-關系 映射,既然O在前關系在后,說明O為重,關系是根據O得來的,那么我們就先新建一些Entity Object吧。在一個博客系統里最常見的就是User,Blog,Post。

一個用戶有且僅有一個博客,而一個博客可以有零篇或者多篇博客文章。根據這個描述我們來建立Entity:

Step 1 建立實體對象

User
/**////
/// 用戶類
///
public class User
{
/**////
/// 用戶標識
///
public int Id { get; set; }
/**////
/// 該用戶對應的博客,
/// 一個用戶有且僅有一個博客
///
public Blog Blog { get; set; }
/**////
/// 用戶名
///
public string UserName { get; set; }
/**////
/// 密碼
///
public string Password { get; set; }
/**////
/// 昵稱
///
public string NickName { get; set; }
/**////
/// 用戶離開時間
///
public DateTime LeaveTime { get; set; }
}

Blog
/**////
/// 博客類
///
public class Blog
{
/**////
/// 博客標識
///
public int Id { get; set; }
/**////
/// 用戶標識,和用戶相關聯
///
public int UserId { get; set; }
/**////
/// 博客的中文名
///
public string Name { get; set; }
/**////
/// 創建時間
///
public DateTime CreateDate { get; set; }
/**////
/// 一個博客有零篇或多篇文章
///
public IList<Post> Posts { get; set; }
}
Code
/**////
/// 博客文章類
///
public class Post
{
/**////
/// 文章Id
///
public int Id { get; set; }
/**////
/// 文章從屬的博客
///
public int BlogId { get; set; }
/**////
/// 標題
///
public string Title { get; set; }
/**////
/// 內容
///
public string Body { get; set; }
/**////
/// 發表時間
///
public DateTime CreateDate { get; set; }
}

我們先不要談論這個設計是否合理,也不要談論這三個實體是貧血模型還是充血模型。

對象建立好了,我們來建設數據庫表吧:users表,blogs表,posts表(為什么表都用復數?從Rails里學過來的,ActiveRecord模式里,表里每條記錄都對應著一個對象,所以表用復數表示,這是一種約定)

Step 2:創建數據庫表

Users表:

Blogs表:

Posts表:

我們注意到,用戶類里的LeaveTime離開時間在數據庫里并沒有對應的字段,因為這個是用來臨時記路用戶離開離開博客園的時間的,這樣可以用來做一些在線統計,所以無需持久化。

繼續>>下一頁
[第1頁][第2頁][第3頁][第4頁][第5頁]

2
0

請先登錄 提交中…

標簽:LINQ LINQ to SQL

文章列表

走進Linq-Linq to SQL源代碼賞析之Provider的初始化

走進Linq-Linq to SQL源代碼賞析之Provider的初始化

作者: 橫刀天笑 來源: 博客園 發布時間: 2008-09-24 12:03 閱讀: 6574 次 推薦: 0 原文鏈接 [收藏]

[1] 走進Linq-Linq to SQL源代碼賞析之Provider的初始化
[2] 走進Linq-Linq to SQL源代碼賞析之Provider的初始化
[3] 走進Linq-Linq to SQL源代碼賞析之Provider的初始化

系列文章導航:

走進Linq–Linq橫空出世篇

走進Linq-輝煌的背后

走進Linq-Linq大觀園

不能不說的C#特性-對象集合初始化器

不能不說的C#特性-匿名類型與隱式類型局部變量

不能不說的C#特性-擴展方法

不能不說的C#特性-匿名方法和Lambda表達式

不能不說的C#特性-迭代器(上)及一些研究過程中的副產品

不能不說的C#特性-迭代器(下),yield以及流的延遲計算

走進Linq-Linq to Objects(上)基礎篇

走進Linq-Linq to Objects(下)實例篇

走進Linq-Linq to SQL感性認識篇

走進Linq-Linq to SQL How do I(1)

走進Linq-Linq to SQL How do I(2)

走進Linq-Linq to SQL How do I(3)

走進Linq-How do I(4)拾遺補零篇第一節

走進Linq-Linq to SQL源代碼賞析 Table的獲取過程

走進Linq-Linq to SQL源代碼賞析之Provider的初始化

走進Linq-Linq to SQL源代碼賞析,通過Linq to SQL看Linq

話說Linq to SQL理論上應該支持多種數據庫的,而且應該支持多種數據庫,到最后卻落的這個局面,是為了商業考慮還是本來技術就不成熟?不得而知。不過不管怎么說Linq to SQL的體系結構確實是支持擴展的。

在System.Data.Linq.Mapping這個命名空間下微軟提供了一個特性:ProviderAttribute,使用強類型的DataContext或使用Xml做映射的時候,該特性可以用來指定具體的數據庫提供者。如下:

[Database(“dbo.cnblogs”)]
[Provider(typeof(SqlProvider))]
Public CnBlogDataContext : DataContext
{

}

這就表明我們的Linq to SQL是基于Sql Server數據庫了,SqlProvider是實現了IProvider接口的(該接口存在于System.Data.Linq.Provider命名空間下)。

在DataContext初始化時執行的Init方法里有這樣幾行代碼:

if (model.ProviderType == null)
{
throw Error.ProviderTypeNull();
}
Type providerType = model.ProviderType;
if (!typeof(IProvider).IsAssignableFrom(providerType))
{
throw Error.ProviderDoesNotImplementRequiredInterface(providerType,
typeof(IProvider));
}
this.provider = (IProvider) Activator.CreateInstance(providerType);
this.provider.Initialize(this.services, connection);

這里是根據model的ProviderType創建一個IProvider的實例。Model就是一個MetaModel對象。前面兩篇都提到了MetaModel有兩個子類,AttributeMetaModel和XmlMetaModel,看看你是用哪種方法做映射的,我們這里就用AttributeMetaModel做例子,在AttributeMetaModel的構造函數里有這樣幾行代碼:

ProviderAttribute[] customAttributes = (ProviderAttribute[]) this.contextType.
GetCustomAttributes(typeof(ProviderAttribute), true);
if ((customAttributes != null) && (customAttributes.Length == 1))
{
this.providerType = customAttributes[0].Type;
}
else
{
this.providerType = typeof(SqlProvider);
}

從DataContext類上找Provider特性,如果沒有找到就默認使用SqlProvider了。創建了IProvider的實例就會調用它的Initialize方法進行初始化。Initialize方法需要兩個參數IDataService和一個連接對象(DbConnection或是連接字符串)。

繼續>>下一頁
[第1頁][第2頁][第3頁]

0
0

請先登錄 提交中…

標簽:LINQ LINQ to SQL Code

文章列表

LINQ to SQL語句(10)之Insert

LINQ to SQL語句(10)之Insert

作者: 李永京 來源: 博客園 發布時間: 2008-09-18 15:59 閱讀: 17825 次 推薦: 0 原文鏈接 [收藏]
摘要:這個系列的第十篇,講解Insert用法。

系列文章導航:

LINQ to SQL語句(1)之Where

LINQ to SQL語句(2)之Select/Distinct

LINQ to SQL語句(3)之Count/Sum/Min/Max/Avg

LINQ to SQL語句(4)之Join

LINQ to SQL語句(5)之Order By

LINQ to SQL語句(6)之Group By/Having

LINQ to SQL語句(7)之Exists/In/Any/All/Contains

LINQ to SQL語句(8)之Concat/Union/Intersect/Except

LINQ to SQL語句(9)之Top/Bottom和Paging和SqlMethods

LINQ to SQL語句(10)之Insert

LINQ to SQL語句(11)之Update

LINQ to SQL語句(12)之Delete和使用Attach

LINQ to SQL語句(13)之開放式并發控制和事務

LINQ to SQL語句(14)之Null語義和DateTime

LINQ to SQL語句(15)之String

LINQ to SQL語句(16)之對象標識

LINQ to SQL語句(17)之對象加載

LINQ to SQL語句(18)之運算符轉換

LINQ to SQL語句(19)之ADO.NET與LINQ to SQL

LINQ to SQL語句(20)之存儲過程

LINQ to SQL語句(21)之用戶定義函數

LINQ to SQL語句(22)之DataContext

LINQ to SQL語句(23)之動態查詢

LINQ to SQL語句(24)之視圖

LINQ to SQL語句(25)之繼承

LINQ簡介

adsfsaf

插入(Insert)

1.簡單形式

說明:new一個對象,使用InsertOnSubmit方法將其加入到對應的集合中,使用SubmitChanges()提交到數據庫。

NorthwindDataContext db = new NorthwindDataContext(); var newCustomer = new Customer { CustomerID = "MCSFT", CompanyName = "Microsoft", ContactName = "John Doe", ContactTitle = "Sales Manager", Address = "1 Microsoft Way", City = "Redmond", Region = "WA", PostalCode = "98052", Country = "USA", Phone = "(425) 555-1234", Fax = null }; db.Customers.InsertOnSubmit(newCustomer); db.SubmitChanges();

語句描述:使用InsertOnSubmit方法將新客戶添加到Customers 表對象。調用SubmitChanges 將此新Customer保存到數據庫。

2.一對多關系

說明:Category與Product是一對多的關系,提交Category(一端)的數據時,LINQ to SQL會自動將Product(多端)的數據一起提交。

var newCategory = new Category { CategoryName = "Widgets", Description = "Widgets are the ……" }; var newProduct = new Product { ProductName = "Blue Widget", UnitPrice = 34.56M, Category = newCategory }; db.Categories.InsertOnSubmit(newCategory); db.SubmitChanges();

語句描述:使用InsertOnSubmit方法將新類別添加到Categories表中,并將新Product對象添加到與此新Category有外鍵關系的Products表中。調用SubmitChanges將這些新對象及其關系保存到數據庫。

3.多對多關系

說明:在多對多關系中,我們需要依次提交。

var newEmployee = new Employee { FirstName = "Kira", LastName = "Smith" }; var newTerritory = new Territory { TerritoryID = "12345", TerritoryDescription = "Anytown", Region = db.Regions.First() }; var newEmployeeTerritory = new EmployeeTerritory { Employee = newEmployee, Territory = newTerritory }; db.Employees.InsertOnSubmit(newEmployee); db.Territories.InsertOnSubmit(newTerritory); db.EmployeeTerritories.InsertOnSubmit(newEmployeeTerritory); db.SubmitChanges();

語句描述:使用InsertOnSubmit方法將新雇員添加到Employees 表中,將新Territory添加到Territories表中,并將新EmployeeTerritory對象添加到與此新Employee對象和新Territory對象有外鍵關系的EmployeeTerritories表中。調用SubmitChanges將這些新對象及其關系保持到數據庫。

4.使用動態CUD重寫(Override using Dynamic CUD)

說明:CUD就是Create、Update、Delete的縮寫。下面的例子就是新建一個ID(主鍵)為32的Region,不考慮數據庫中有沒有ID為32的數據,如果有則替換原來的數據,沒有則插入。

Region nwRegion = new Region() { RegionID = 32, RegionDescription = "Rainy" }; db.Regions.InsertOnSubmit(nwRegion); db.SubmitChanges();

語句描述:使用DataContext提供的分部方法InsertRegion插入一個區域。對SubmitChanges 的調用調用InsertRegion 重寫,后者使用動態CUD運行Linq To SQL生成的默認SQL查詢。

0
0

請先登錄 提交中…

標簽:LINQ LINQ to SQL

文章列表

一步一步學Silverlight :使用Transform實現更炫的效果(下)

一步一步學Silverlight :使用Transform實現更炫的效果(下)

作者: TerryLee 來源: 博客園 發布時間: 2008-10-09 10:31 閱讀: 9808 次 推薦: 2 原文鏈接 [收藏]

[1] 一步一步學Silverlight :使用Transform實現更炫的效果(下)
[2] 一步一步學Silverlight :使用Transform實現更炫的效果(下)
[3] 一步一步學Silverlight :使用Transform實現更炫的效果(下)

概述

Silverlight 2 Beta 1版本發布了,無論從Runtime還是Tools都給我們帶來了很多的驚喜,如支持框架語言Visual Basic, Visual C#, IronRuby, Ironpython,對JSON、Web Service、WCF以及Sockets的支持等一系列新的特性。《一步一步學Silverlight 2系列》文章將從Silverlight 2基礎知識、數據與通信、自定義控件、動畫、圖形圖像等幾個方面帶您快速進入Silverlight 2開發。

本文為使用Transform實現更炫的效果第二部分,在Silverlight中提供了四種基本變換:旋轉變換(RotateTransform )、縮放變換(ScaleTransform)、傾斜變換(SkewTransform)、移動變換(TranslateTransform)和兩種復雜的變換:變換組(TransformGroup)、矩陣變換(MatrixTransform ),這些變換可以運用到任何控件或者圖形圖像。

矩陣變換(MatrixTransform )

矩陣變換MatrixTransform是所有變換中功能最強大最靈活也是最復雜的一種變換,如果前面講解的幾種基本變化不能滿足我們在實際開發中的需求,可以使用矩陣變換進行自定義,它允許我們直接對變換矩陣進行操作。

在Silverlight中,變換是提供一個3*3的矩陣,我們通過修改矩陣中成員的值來實現變換,矩陣的定義如下所示:

TerryLee_Silverlight2_0148

如修改OffsetX,元素將會在X軸上進行移動;修改OffsetY,元素將在Y軸上移動;修改M22為2,元素的高度將會拉伸2倍,通過該矩陣,我們能實現前面提到的幾種基本變換的所有功能。更詳細的解釋大家可以參考SDK。如下面的例子,我們使用矩陣變換,仍然能實現前面示例中的變換效果:

<Canvas Background="#CDFCAE"> <Image Source="a1.png" Canvas.Left="120" Canvas.Top="50" Opacity="0.3"> </Image> <Image Source="a1.png" Canvas.Left="120" Canvas.Top="50" Opacity="0.5"> <Image.RenderTransform> <MatrixTransform> <MatrixTransform.Matrix> <Matrix OffsetX="0" OffsetY="0" M12="0.2"></Matrix> </MatrixTransform.Matrix> </MatrixTransform> </Image.RenderTransform> </Image> <Image Source="a1.png" Canvas.Left="120" Canvas.Top="50"> <Image.RenderTransform> <MatrixTransform> <MatrixTransform.Matrix> <Matrix OffsetX="0" OffsetY="0" M12="0.4"></Matrix> </MatrixTransform.Matrix> </MatrixTransform> </Image.RenderTransform> </Image> </Canvas>

運行后效果如下:

TerryLee_Silverlight2_0149

繼續>>下一頁
[第1頁][第2頁][第3頁]

2
0

請先登錄 提交中…

標簽:Silverlight Transform

文章列表

使用Mono.Cecil輔助ASP.NET MVC使用dynamic類型Model

使用Mono.Cecil輔助ASP.NET MVC使用dynamic類型Model

作者: 老趙 發布時間: 2011-10-20 17:10 閱讀: 6759 次 推薦: 2 原文鏈接 [收藏]

  這也是之前在珠三角技術沙龍上的示例之一,解決的是在ASP.NET MVC使用dynamic類型Model時遇到的一個真實問題。C# 4編譯器支持dynamic類型,因此在編寫頁面模板的時候自然就可以把它作為視圖的Model類型。表現層的需求很容易改變,因此dynamic類型的Model可以減少我們反復修改強類型Model的麻煩,再配合匿名類型的使用,可謂是動靜相宜,如魚得水。不過,如果把一個匿名類型直接作為Model交給視圖去使用,在默認情況下會拋出異常。我們可以用Mono.Cecil來改變這一情況。

  在視圖中使用dynamic類型Model

  我們先來重現這個問題。創建一個使用C# 4的ASP.NET MVC網站,添加如下的Controller,其中把匿名類型作為視圖Model:

public class HomeController : Controller
{
public ActionResult Index(string title = “<<Default>>")
{
return View(new { Title = title });
}
}

  并定義一個Index.aspx作為視圖模板,Model類型作為dynamic,并用到Title:

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>"%>
<!DOCTYPE html>
<html>
<head runat="server">
<title>Index</title>
</head>
<body>
<h1><%: Model.Title %></h1>
</body>
</html>

  按理來說,這么做應該一切正常,但是運行之后便會提示說Model上找不到Title成員:

  這又是什么原因呢?

  訪問級別與成員

  在C# 4出現之前,我們也完全可以構造一個Model類型作為視圖的模型,例如:

public class IndexModel
{
public string Title { get; set; }
}

  使用這種做法便完全可以正常運行通過了。那么為什么具體類型能夠正常工作,而匿名類型卻失敗了呢?“按常理推斷”它們不都是普通的類型,然后訪問它們的屬性嗎?我們用ILSpy查看使用匿名類型編譯后的結果,可以發現匿名類型與上面的IndexModel有一個重要的不同之處:

  由于是“匿名類型”,顯然它的訪問級別應該是internal的,這樣它就能對外“隱藏”起來了。但是這就給ASP.NET MVC的視圖帶來了麻煩。因為ASP.NET MVC的視圖會在運行時動態地編譯aspx為額外的dll,因此它是無法訪問到Controller所在程序集的internal成員的。經試驗,如果我們將之前的IndexModel的訪問級別修改為internal便會得到相同的結果。

  額外提一句,類似的代碼在Mono下卻可以運行通過。這意味著在動態訪問對象成員的時候,Mono和.NET在訪問級別方面的檢查是有所不同的。雖然在這個情景里Mono更方便,但理論上說,.NET的做法實則更合理。

  使用NuGet安裝Mono.Cecil

  Mono.Cecil是Mono的組件之一,用來編輯.NET程序集文件。我們可以用它來打探一個.NET程序集內部的結構,就像反射那樣,只不過并不需要將程序集加載進來,Mono.Cecil只是讀取文件物理內容而已。例如,上圖所用的ILSpy便用到了Mono.Cecil。更重要的是,Mono.Cecil可以修改并保存程序集,這便可以讓我們實現各種奇形怪狀的要求。像這篇文章所提到的,只不過是小試牛刀而已。

  Mono和.NET是二進制兼容的,因此我們可以直接把Mono下的Mono.Cecil.dll復制并引用到.NET程序里。不過這么做還是麻煩了,如今在.NET平臺上使用各種組件已經有更方便的做法:使用包管理器。.NET平臺下的包管理器叫做NuGet,是由SubText的作者,后來被微軟聘用作ASP.NET MVC程序經理的Phil Haack帶頭開發的開源項目。NuGet提供了Visual Studio的擴展,同時也有基于PowerShell的命令行。這里我們就從Visual Studio的擴展開始使用吧。

  創建一個名為PublicAnonymous的控制臺項目,并選擇Reference – Manage NuGet Packages:

  搜索Mono.Cecil,并安裝即可:

  NuGet會自動處理組件之間的依賴及項目的配置,您也可以自己把玩一番。

  使用Mono.Cecil修改程序集

  有了Mono.Cecil我們便可以修改程序集了,只需數行代碼:

static void Main(string[] args)
{
var asmFile = args[0];
Console.WriteLine("Making anonymous types public for '{0}'.", asmFile);

var asmDef = AssemblyDefinition.ReadAssembly(asmFile, new ReaderParameters
{
ReadSymbols = true
});

var anonymousTypes = asmDef.Modules
.SelectMany(m => m.Types)
.Where(t => t.Name.Contains("<>f__AnonymousType"));

foreach (var type in anonymousTypes)
{
type.IsPublic = true;
}

asmDef.Write(asmFile, new WriterParameters
{
WriteSymbols = true
});
}

  首先,從參數中獲取需要修改的程序集名稱,找到所有的匿名類型,并將其訪問級別設為Public后保存。保存的時候將WriteSymbols參數設為true,這樣它也會同時修改pdb文件——這很重要,否則修改后的程序集無法和pdb文件內容相對應,便無法調試了。換句話說,Mono.Cecil也能正確處理pdb文件。

  最后,只要在ASP.NET MVC網站編譯時使用這個項目即可,只需配置一下它的Post Build事件:

  再次編譯并運行程序,即可得到正確結果。再拿ILSpy來檢查一番:

  總結

  在沙龍上,有朋友問我怎么樣可以成為一個高級.NET技術人員。我不知道“如何成為”,但我想,了解整個生態環境的發展情況,了解.NET的優勢及不足,甚至能夠了解相關領域其他技術方向的發展態勢,應該是優秀.NET程序員的特質之一吧。

  而Mono便是.NET生態環境的重要組成部分。

2
0

請先登錄 提交中…

標簽:MVC Mono dynamic

文章列表