Webservice WCF WebApi 前端數據可視化 前端數據可視化 C# asp.net PhoneGap html5 C# Where 網站分佈式開發簡介 EntityFramework C

Webservice WCF WebApi

 

註明:改編加組合javascript

 

在.net平臺下,有大量的技術讓你建立一個HTTP服務,像Web Service,WCF,如今又出了Web API。在.net平臺下,你有不少的選擇來構建一個HTTP Services。我分享一下我對Web Service、WCF以及Web API的見解。html

  Web Service前端

  一、它是基於SOAP協議的,數據格式是XMLhtml5

  二、只支持HTTP協議java

  三、它不是開源的,但能夠被任意一個瞭解XML的人使用node

  四、它只能部署在IIS上python

 

  WCFjquery

  一、這個也是基於SOAP的,數據格式是XMLandroid

  二、這個是Web Service(ASMX)的進化版,能夠支持各類各樣的協議,像TCP,HTTP,HTTPS,Named Pipes, MSMQ.ios

  三、WCF的主要問題是,它配置起來特別的繁瑣

  四、它不是開源的,但能夠被任意一個瞭解XML的人使用

  五、它能夠部署應用程序中或者IIS上或者Windows服務中

 

  WCF Rest

  一、想使用WCF Rest service,你必須在WCF中使用webHttpBindings

  二、它分別用[WebGet]和[WebInvoke]屬性,實現了HTTP的GET和POST動詞

  三、要想使用其餘的HTTP動詞,你須要在IIS中作一些配置,使.svc文件能夠接受這些動詞的請求

  四、使用WebGet經過參數傳輸數據,也須要配置。並且必須指定UriTemplate

  五、它支持XML、JSON以及ATOM這些數據格式

 

  Web API

  一、這是一個簡單的構建HTTP服務的新框架

  二、在.net平臺上Web API 是一個開源的、理想的、構建REST-ful 服務的技術

  三、不像WCF REST Service.它可使用HTTP的所有特色(好比URIs、request/response頭,緩存,版本控制,多種內容格式)

  四、它也支持MVC的特徵,像路由、控制器、action、filter、模型綁定、控制反轉(IOC)或依賴注入(DI),單元測試。這些可使程序更簡單、更健壯

  五、它能夠部署在應用程序和IIS上

  六、這是一個輕量級的框架,而且對限制帶寬的設備,好比智能手機等支持的很好

  七、Response能夠被Web API的MediaTypeFormatter轉換成Json、XML 或者任何你想轉換的格式。

  

  WCF和WEB API我該選擇哪一個?

  一、當你想建立一個支持消息、消息隊列、雙工通訊的服務時,你應該選擇WCF

  二、當你想建立一個服務,能夠用更快速的傳輸通道時,像TCP、Named Pipes或者甚至是UDP(在WCF4.5中),在其餘傳輸通道不可用的時候也能夠支持HTTP。

  三、當你想建立一個基於HTTP的面向資源的服務而且可使用HTTP的所有特徵時(好比URIs、request/response頭,緩存,版本控制,多種內容格式),你應該選擇Web API

  四、當你想讓你的服務用於瀏覽器、手機、iPhone和平板電腦時,你應該選擇Web API

  

  原文:http://www.dotnet-tricks.com/Tutorial/webapi/JI2X050413-Difference-between-WCF-and-Web-API-and-WCF-REST-and-Web-Service.html

 

Web API = Web Service - 服務定義,換言之 Web API + 服務定義 = Web Service。

少了服務定義會怎樣?

  1. 沒法發現服務,從而也沒法知曉服務的變動和刪除。但,這樣又如何?服務發現原本就是UDDI而非WSDL作的事情。
  2. 沒法得到數據類型的定義。Web API在這方面使用XML或者json直接傳輸數據而無須預先定義,這兩個都是弱類型的語言:
    • 好處,再複雜的類型(只要不是循環引用)都輕鬆的搞定
    • 很差不壞,基礎類型都有,通用性十足(WSDL也有,並且只須要作一次)
    • 壞處,沒有動態語言功底的環境,每次都須要解析比較吃力(WS有了WSDL,這種事情只須要作一次)
  3. 沒法得到消息結構的定義。正如2中描述的那樣,若是描述一個數據那麼複雜,又何須爲了它創建一個公開接口定義?相應的,若是描述很容易,也沒有必要去事先定義。
  4. 沒法定義多個操做。。。對於調用API的人來講沒有任何做用。
  5. 沒法定義多個站口/通信協議。這也是個贅飾。

少了服務定義又會怎樣?

  1. 仍然須要一個服務的源來暴露服務。做爲一個服務提供商,這是理所固然要作的事情。
  2. 數據類型的定義。只要不出現循環引用,一切都簡單到不能更簡單。
  3. 服務接口的定義。也許咱們沒法提供在線的代碼框架生成,但咱們能夠提供手冊+現成的接口調用代碼。

固然具體到WS的表明SOAP與WebAPI的表明json。PK不會發生在Soap->Http Header VS Http Header(結果同樣),就只有Soap Body->Http Body->XML vs Http Body->json了。這二者沒什麼可說的,json基本上是完勝。

因此,一個一般的服務提供商,json形式的Web API加上統一的源管理,賽過soap+http的Web Service。不要扯什麼安全性,你們都是http基礎;若是認爲json可以跨域就叫「不安全」,那他應該弄明白怎麼樣才能跨域。

 

前端數據可視化

 

原文

在大數據時代,不少時候咱們須要在網頁中顯示數據統計報表,從而能很直觀地瞭解數據的走向,開發人員不少時候須要使用圖表來表現一些數據。隨着Web技術的發展,從傳統只能依靠於flash、IE的vml,各個瀏覽器尚不統一的svg,到現在規範統一的canvas、svg爲表明的html5技術,表現點、線、面要素的技術已經愈來愈規範成熟。我把前端數據可視化分爲了五種:
1.圖表
2.圖譜
3.地圖
4.關係圖
5.立體圖
我將按照順序介紹62款前端可視化插件,下面就分享下34款圖表插件:
1.amcharts
url: http://www.amcharts.com/
browser:IE6+、chrome、safari、firefox、opear
resume:amCharts是一種先進的圖表庫,將適合任何數據可視化的須要。圖表解決方案包括柱、欄、線、區域,一步,一步沒有冒口,平滑線,燭臺,OHLC,餡餅/甜甜圈,雷達/極地,XY /分散/泡沫,子彈,漏斗/金字塔圖以及指標。

2.awesomechartjs
url:http://cyberpython.github.io/AwesomeChartJS/
github:https://github.com/cyberpython/AwesomeChartJS
browser:現代瀏覽器
resume:AwesomeChartJS是一個簡單的Javascript庫,可用於建立圖表基於HTML 5畫布元素。

3.axiis
url:http://www.axiis.org/
browser:官方未說明
resume:Axiis框架是一個開源的數據可視化爲初學者和專家開發人員設計的。

4.bonsaijs
url:http://bonsaijs.org/
github:https://github.com/uxebu/bonsai
browser:IE9+、chrome20+、safari5+、firefox18+、opear12+
resume:用於建立圖形和動畫的js庫

5.canvasjs
url:http://canvasjs.com
browser:官方未說明
resume:一個使用HTML五、JavaScript建立圖表在畫布上,圖表包括幾個好看的主題和10倍的速度比傳統的基於Flash / SVG庫——致使輕量級的,美麗的和響應指示板。收費

6.canvasxpress
url:http://canvasxpress.org/
browser:Firefox 1.5+, Opera 9+, Safari 3.x+, Chrome 1.0+, IE 6+
resume:CanvasXpress是一個獨立的Javascript編寫的圖形庫,支持全部主流瀏覽器中計算機和移動設備。

7.chartist
url:http://gionkunz.github.io/chartist-js/
github:https://github.com/gionkunz/chartist-js
browser:Firefox, Chrome, Safari, Opera, IE9+
resume:繪製多種圖形的庫

8.chartjs
url:http://www.chartjs.org/
github:https://github.com/nnnick/Chart.js
browser:IE9+、chrome、safari、firefox、opear、部分支持IE7/8
resume:chartjs是一個能夠繪製多種圖表的庫,使用了html5的canvas技術

9.chartkick
url:http://ankane.github.io/chartkick/
github:https://github.com/ankane/chartkick
browser:IE6+、chrome、safari、firefox、opear
resume:chartkick是一個依賴於ruby的繪製圖表的js庫,在Python中也可使用

10.DataWrapper
url:https://datawrapper.de/
github:https://github.com/datawrapper/datawrapper
browser:支持大部分瀏覽器
resume:Datawrapper徹底免費,開源。您可使用他們的免費主機服務,或者安裝在您本身的服務器上。Datawrapper用PHP編寫,很是易於安裝、修改和拓展。能夠繪製。可是DataWrapper是生成圖表後嵌入到站點的。

11.dataset
url:http://misoproject.com/dataset/
github:https://github.com/misoproject/dataset
browser:官方未說明
resume:dataset是一個JavaScript客戶端數據轉換和管理庫。數據集管理客戶端數據簡單處理加載、解析、排序、查詢和操縱來自各類數據源的數據。

12.dc
url:http://dc-js.github.io/dc.js/
github:https://github.com/dc-js/dc.js
browser:官方未說明
resume:專門爲探索大型、多維數據集而進行優化的庫

13.dygraphs
url:http://dygraphs.com/
browser:IE8+、chrome、safari、firefox、opear
resume:dygraphs是一種快速、靈活的開源JavaScript庫圖表。

14.echart
url:http://echarts.baidu.com/index.html
github:https://github.com/ecomfe/echarts
browser:IE9+、chrome、safari、firefox、opear
resume:基於Canvas,純Javascript圖表庫,提供直觀,生動,可交互,可個性化定製的數據可視化圖表。創新的拖拽重計算、數據視圖、值域漫遊等特性大大加強了用戶體驗,賦予了用戶對數據進行挖掘、整合的能力。

15.flotr2
url:http://www.humblesoftware.com/flotr2/
github:https://github.com/HumbleSoftware/Flotr2
browser:FF, Chrome, IE6+, Android, iOS
resume:Flotr2是HTML5畫圖表和圖形庫。能夠繪製線圖、條圖、蠟狀圖、餅圖、氣泡圖

16.Flot
url:http://www.flotcharts.org/
browser:Internet Explorer 6+, Chrome, Firefox 2+, Safari 3+ and Opera 9.5+
resume:一個基於jQuery的繪圖庫,能夠繪製折線、散點、條形、餅狀圖

17.fusioncharts
url:http://www.fusioncharts.com/
browser:IE6+、chrome、safari、firefox、opear
resume:一個專門用來繪製圖表的庫,能夠繪製90多種圖表,可是收費

18.graphael
url:http://g.raphaeljs.com/
browser:Firefox 3.0+, Safari 3.0+, Opera 9.5+ and Internet Explorer 6.0+

resume:能夠繪製各類圖表的插件,並且很是簡單靈活

19.highchart
url:http://www.highcharts.com/
github:https://github.com/highslide-software/highcharts.com/
browser:支持各類設備,ie6+
resume:在高版本瀏覽器中使用SVG,而在舊版本IE(包括IE6及更新版本)中使用後備的VML。有本身的團隊負責,可是隻對非商業用途免費,能夠繪製 line, spline, area, areaspline, column, bar, pie, scatter, angular gauges, arearange, areasplinerange, columnrange, bubble, box plot, error bars, funnel, waterfall and polar chart types

20.humble Finance
url:http://www.humblesoftware.com/finance/index
browser:FireFox, Safari, Chromium, or IE6+
resume:HumbleFinance是一個HTML5數據可視化工具相似於Flash工具,徹底是用JavaScript編寫的工具使用原型和Flotr庫。

21.ichartjs
url:http://www.ichartjs.com/
github:https://github.com/wanghetommy/ichartjs
browser:IE9+、chrome、safari、firefox、opear
resume:ichartjs 是一款基於HTML5的圖形庫。使用純javascript語言, 利用HTML5的canvas標籤繪製各式圖形。 ichartjs致力於爲您的應用提供簡單、直觀、可交互的體驗級圖表組件。ichartjs目前支持餅圖、環形圖、折線圖、面積圖、柱形圖、條形圖。

22.icharts
url:http://www.icharts.net/
browser:官方未說明
resume:iCharts免費版本提供了一些基本的交互式圖表樣式,若是更使用高級的樣式,則須要購買高級版本。

23.JavaScript InfoVis Toolkit
url:http://philogb.github.io/jit/
github:https://github.com/philogb/jit
browser:官方未給出具體版本
resume:JavaScript InfoVis Toolkit能夠動態繪製各類圖形,提供了一些預設的樣式可用於展現不一樣的數據

24.jqplot
url:http://www.jqplot.com/
browser:IE 7+, Firefox, Safari, and Opera
resume:基於jQuery的繪圖插件,能夠繪製折線、條形、散點、餅狀圖

25.jscharts
url:http://www.jscharts.com/
browser:Firefox 1.5 +,Chrome 10 +,Internet Explorer 8 +,Safari 3.1 +,Opera 9 +
resume:jscharts是一個基於JavaScript的圖表生成器,須要不多或根本沒有編碼。jscharts繪製圖表是一個簡單和容易的任務,由於您只須要使用客戶端腳本(即由web瀏覽器)。不須要額外的插件或服務器模塊。就包括咱們的腳本,準備你的圖表數據XML、JSON或JavaScript數組和你的表已經準備好了!容許您建立圖柱狀圖,餅圖或簡單的線條圖。收費可是有免費版本。

26.kendo-ui
url:http://www.telerik.com/kendo-ui
github:https://github.com/telerik/kendo-ui-core
browser:現代瀏覽器
resume:http://www.cnblogs.com/xiyangbaixue/p/3951297.html

27.nvd3
url:http://nvd3.org/
github:https://github.com/novus/nvd3
browser:Chrome,Firefox, Opera, Safari and Internet Explorer 10
resume:d3圖表庫

28.pizza-pie-charts
url:http://zurb.com/playground/pizza-pie-charts
github:https://github.com/zurb/pizza
browser:官方未說明
resume:主要用來生成餅狀圖的庫

29.protovis
url:http://mbostock.github.io/protovis/
github:https://github.com/mbostock/protovis
browser:現代瀏覽器
resume:Protovis組成自定義視圖的數據用簡單的標誌如酒吧和點。與低級圖形庫,迅速成爲可視化乏味,Protovis定義是經過編碼數據的動態屬性,容許繼承,尺度和layoutsto簡化施工。

30.Peity
url:http://benpickles.github.io/peity/
browser:Chrome, Firefox, IE9+, Opera, Safari
resume:能夠繪製多種圖形,可是都是很小的圖形,與jQuery Sparklines類似

31.rgraph
url:http://www.rgraph.net/
browser:現代瀏覽器
resume:RGraph是一個基於HTML5的開放web圖表和圖表庫。RGraph建立這些圖表在web瀏覽器使用JavaScript,這意味着更快的頁面和web服務器負載,致使較小的頁面大小和更快的網站。

32.webfx
url:http://webfx.eae.net/
browser:Firefox 1.5, Opera 9 and Internet Explorer 6
resume:支持多種圖表的庫

33.xcharts
url:http://tenxer.github.io/xcharts/
github:https://github.com/tenXer/xcharts/
browser:現代瀏覽器
resume:xCharts美麗是一個JavaScript庫,用於構建和自定義數據驅動的web使用D3.js圖表可視化。使用HTML、CSS和SVG,xCharts被設計成動態、流體、集成和定製。

34.zingchart
url:http://www.zingchart.com/
browser:官方未聲明
resume:ZingChart創造驚人的可視化提供了靈活性和資源。提供超過100個圖表類型,獨特的特性,如縮放和交互式。


小結:

每款插件各有千秋,根據項目需求挑選不一樣插件。其中比較普遍使用的如echart(百度產品)、highchart等,下面我將分享圖譜插件。
9款圖譜插件:
1.crossfilter
url:http://square.github.io/crossfilter/
github:https://github.com/square/crossfilter
browser:官方未說明
resume:一個能夠操做大型、多元數據集的庫,幫助數據分析。

2.d3js
url:http://d3js.org/
github:https://github.com/mbostock/d3
browser:Firefox, Chrome, Safari, Opera, IE9+
resume:D3.js是一個JavaScript庫,基於數據操做文檔。D3能夠幫助你把數據使用HTML、SVG和CSS。D3強調web標準給你完整的現代瀏覽器的功能沒有把本身和一個專有的框架,結合強大的可視化組件和DOM操做的數據驅動的方法。

3.envisionjs
url:http://www.humblesoftware.com/envision/index
github:https://github.com/HumbleSoftware/envisionjs
browser:IE6+、chrome、safari、firefox、opear
resume:envisionjs是一個庫來建立快速、動態和交互式可視化的圖表

4.jsxgraph
url:http://jsxgraph.uni-bayreuth.de/wp/
github:https://github.com/jsxgraph/jsxgraph
browser:現代瀏覽器
resume:JSXGraph交互式幾何是一個跨瀏覽器的庫,函數繪圖,圖表和數據可視化在web瀏覽器中。它徹底實如今JavaScript中,不依賴於任何其餘庫,並使用SVG VML或畫布上。

5.paperjs
url:http://paperjs.org/
github:https://github.com/paperjs/paper.js
browser:IE9+,chrome,firefox
resume:paperjs是一款不可多得的js插件,能夠繪製各類動態圖形效果

6.processingjs
url:http://processingjs.org/
github:https://github.com/processing-js/processing-js/
browser:現代瀏覽器
resume:processingjs是用Java編寫的,因此圖形在網頁上顯示要靠Java程序,使用canvas技術

7.Raphaël
url:http://raphaeljs.com/
github:
browser:Firefox 3.0+, Safari 3.0+, Chrome 5.0+, Opera 9.5+ and Internet Explorer 6.0+.
resume:Raphaël是一款繪製矢量圖的插件,支持低版本的瀏覽器

8.sparklines
url:http://omnipotent.net/jquery.sparkline/#s-about
github:
browser:Firefox 2+, Safari 3+, Opera 9, Chrome and Internet Explorer 6+,ios和andriod設備
resume:使用內嵌在HTML中的數據或經過javascript直接生成微線圖(小內聯圖表),最主要的特色是能夠生成波形圖。

9.tangle
url:http://worrydream.com/Tangle/
github:
browser:
resume:Tangle是一個JavaScript庫,用於建立活性文檔。讀者能夠交互式地探索可能性,玩參數,並當即看到文檔更新。Tangle是超級簡單,容易學習。


小結:後面將分享6款地圖插件。

6款地圖插件:
1.Kartograph
url:http://kartograph.org/
github:https://github.com/kartograph/kartograph.py
browser:Internet Explorer 7+,chrome,Firefox
resume:Gregor Aisch開發的一個基於JavaScript和Python的很是炫的、徹底使用矢量的庫。

2.leafletjs
url:http://leafletjs.com/
github:https://github.com/Leaflet/Leaflet
browser:Chrome,Firefox,Safari 5+,Opera 12+,IE 7–11
resume:leafletjs是一個開源的支持移動端的地圖插件,js文件僅僅有33kb,

3.Modest Maps
url:http://modestmaps.com/
github:https://github.com/modestmaps/modestmaps-js
browser:Firefox, Chrome, Opera, iOS, Android, and Internet Explorer 7-9.
resume:Modest Maps支持各類設備,也有不少版本。雖然是一款老的地圖插件,可是很是小、可擴展並且免費

4.polymaps
url:http://polymaps.org/
github:https://github.com/simplegeo/polymaps
browser:現代瀏覽器
resume:Polymaps依賴於SVG,所以在較新的瀏覽器中表現很好。

5.imagemapster
url:http://www.outsharked.com/imagemapster/
browser:Firefox, Chrome, Safari, Opera, IE6+
resume:ImageMapster是一個jQuery插件,它使你的HTML圖片像Flash同樣炫

6.datavlab
url:http://datavlab.org/
github:https://github.com/TBEDP/datavjs
browser:IE6+、chrome、safari、firefox、opear
resume:datav.js是爲了下降平常對於可視化方法使用的成本,用數據可視化的方法幫助到更多的人。


如今來分享9款關係圖插件:
1.arborjs
url:http://arborjs.org/halfviz/#/a-new-hope
github:https://github.com/samizdatco/arbor
browser:IE6+,chrome,firefox
resume:基於jQuery的圖譜可視化庫,對於高版本的瀏覽器這個庫使用了HTML的canvas元素


2.cubism
url:http://square.github.io/cubism/
github:https://github.com/square/cubism
browser:官方未說明
resume:時間序列數據可視化的D3插件


3.gantti
url:http://bastianallgeier.com/gantti/
github:https://github.com/bastianallgeier/gantti
browser:IE7+、chrome、safari、firefox、opear
resume:是一款PHP的前端數據展現插件


4.getspringy
url:http://getspringy.com/
github:https://github.com/dhotson/springy/
browser:官方未說明
resume:Springy是一個使用JavaScirpt實現的有向圖佈局算法,使用了真實世界中的一些物理原理,你能夠隨意拖動圖表中的元素。


5.graphdracula
url:http://www.graphdracula.net/
github:https://github.com/strathausen/dracula
browser:官方未說明
resume:graphdracula是一組工具來顯示和佈局互動圖表,以及各類相關算法。


6.sigamajs
url:http://sigmajs.org/
github:https://github.com/jacomyal/sigma.js
browser:IE9+,chrome,firefox
resume:一個很是輕量級的圖譜可視化庫。Sigma.js很漂亮,速度也快。


7.smoothiecharts
url:http://smoothiecharts.org/
github:https://github.com/joewalnes/smoothie/
browser:IE7+、chrome、safari、firefox、opear
resume:smoothiecharts是一個很是小的圖表庫爲實時流媒體數據而設計的


8.timeplot
url:http://www.simile-widgets.org/timeplot/
github:
browser:官方未說明
resume:Timeplot是基於dhtml AJAXy部件繪圖時間序列和覆蓋基於時間的事件


9.visjs
url:http://visjs.org/
github:https://github.com/almende/vis/
browser:Chrome, Firefox, Opera, Safari, IE9+
resume:Vis.js是一個動態的、基於瀏覽器可視化庫。庫被設計成易於使用,處理大量的動態數據,使操做和交互的數據。時間表,包括組件庫數據集網絡、Graph2d,Graph3d。

 

C# asp.net PhoneGap html5

 

好久沒寫博客,今天本身寫一篇吧。來談一談c# PhoneGap,html5 與asp.net。能搜到這篇博客就說明你是一位.net開發者,即將或者正在從事移動開發。

你們可能都有疑,我是一名.net開發者,能用.net作蘋果,安卓,wp平臺的應用嗎?

如你們所知,phoneGap是用來開發跨平臺移動應用的,並且phoneGap能調用移動設置的硬件接口,實現一些普通html在移動設備上沒法實現的功能,好比拍照,錄音,錄製視頻等。

要作html5頁面爲單元的應用,必定少不了與服務器進行數據交互。想到的與服務器交互有兩種方案:

一種是使用默認的本地HTML方式(固然也能夠把HTML放在服務器端,可是這樣還不如使用第二種方案),一種是全程使用服務器腳本,好比JSP頁面,固然這些頁面確定是放在服務器端,客戶端只須要在初始化的時候引用這個頁面便可,Android客戶端,代碼以下:

public class MyActivity extends DroidGap { 
  @Override 
  public void onCreate(Bundle savedInstanceState) { 
  super.onCreate(savedInstanceState); 
  //super.loadUrl("file:///android_asset/login.html"); 
  super.loadUrl("http://220.166.32.204:8080/test/login.jsp"); 
  super.setIntegerProperty("loadUrlTimeoutValue", 15000); 
  } 
}

(註釋掉的代碼爲PhoneGap默認的本地HTML方案)

另外一種是http請求即爲服務器腳本解決方案

各有各的好處,本地HTML方案能夠把代碼和服務器端的代碼隔離開,維護只須要維護客戶端,無需修改服務器端,而且由於是本地讀取,能夠在無網絡狀況下使用應用程序(能夠把資源保存在本地sqlLite數據庫中);服務器腳本解決方案好處是代碼簡單,和開發普通web頁面幾乎無差異,甚至能夠直接使用以前針對PC寫好的web頁面,JS識別設備動態更換一下CSS樣式便可。

我使用的是本地HTML5解決方案,在數據交互上,使用的是ajax,使用jQuery的ajax方法,JS代碼以下:

function pullNoticeList(){ 
 $.ajax({ 
  url:addr+"notice_list.action", 
  type:"POST", 
  dataType:"jsonp", 
  data:{"start":"0","limit":"8","sort":"effectiveDate","dir":"DESC"}, 
  beforeSend: function(){ 
  $("#content").html("<p>數據拉取中,請稍後...</p>").trigger("create"); 
  }, 
  success:function(response){ 
  var startHtml = '<ul id="listview" data-role="listview" data-theme="c">'; 
  var endHtml = "<li id='more'><p >; 
  $.each(response.noticeList,function(index,item){ 
  startHtml+="<li><a href='javascript:showDetail("+item.noticeId+");'><p>"+item.noticeTitle+"<span class='ui-li-aside'>"+item.effectiveDate+"</span></p></a></li>"; 
  }); 
  $("#content").html(startHtml+endHtml).trigger("create"); 
  }, 
  error:function(){ 
  showReConnConfirm(); 
  } 
 }); 
}

必須使用jsonp格式,否則無返回值,其次,注意返回的json格式,必定要符合jQuery的json格式,能夠經過firedug查看調試json,服務器端使用的struts,可使用struts的json插件,能夠很智能把對象封裝成json格式。

若是你想用phoneGap作一款跨平臺的應用,首先要肯定會不會調用移動設備的硬件接口,若是不須要調用,那麼第一張方案是最佳的選擇,維護開發與日常web幾乎沒區別,最佳的適合咱們.net開發者,由於咱們能夠直接選擇用aspx頁面來開發。

可是若是項目有要求要調用移動設備的硬件接口,那麼必需要選擇用第二種方案了。

這時,與服務器交互,html5端用ajax,後臺能夠用aspx,或者ashx,或者asmx,即分別對應普通aspx頁面或者通常處理程序ashx頁面,或者直接寫webservice服務都行。但願能幫到你們。

移動開發html5,必將是主流,一塊兒迎接吧!

 

C# Where

 

判斷一個字符串中是否包含字符串數組裏的字符,惡意字符限制提交,通常人,包括最初的我,會這樣寫

 

複製代碼
public bool ValidateStr(string[] parms)
    {

        bool result = false;

        //要驗證的字符列表

        string[] validateParms = { "'", "\"", "%" };
        for (int i = 0; i < parms.Length; i++)
        {
            for (int j = 0; j < validateParms.Length; j++)
            {
                if (parms[i].IndexOf(validateParms[j]) != -1)
                {
                    result = true;
                }
            }
        }
        return result;
    }
複製代碼

 

 

 

 

可是你毫不以爲,看着代碼很亂呢

其實咱們能夠這樣寫

 

複製代碼
  public bool ValidateStr(string[] parms)
    {
        bool result = false;
        //要驗證的字符列表
        string[] validateParms = { "'", "\"", "%" };
        for (int i = 0; i < parms.Length; i++)
        {
            if (validateParms.Where(p => p.IndexOf(parms[i]) > 0).Count() > 0)
            {
                result = true;

            }
        }
        return result;
    }
複製代碼

 

代碼瞬間清晰

 

網站分佈式開發簡介

 

1          概述 分佈式應用程序就是指應用程序分佈在不一樣計算機上,經過網絡來共同完成一項任務,一般爲服務器/客戶端模式。更廣義上理解「分佈」,不僅是應用程序,還包括數據庫等,分佈在不一樣計算機,完成同一個任務。之因此要把一個應用程序分佈在不一樣的計算機上,主要有兩個目的:

1)        分散服務器的壓力

大型系統中,模塊衆多,併發量大,僅用一個服務器承載每每會發生壓力過大而致使系統癱瘓的狀況。能夠在橫向和縱向兩方面來進行拆分,把這些模塊部署到不一樣的服務器上。這樣整個系統的壓力就分佈到了不一樣的服務器上。

l        橫向:按功能劃分。

l        縱向:N層架構,其中的一些層分佈到不一樣的服務器上(分層的概念會在後文進行介紹)。

2)        提供服務,功能重用

使用服務進行功能重用比使用組件進行代碼重用更進一層。舉例來講,若是在一個系統中的三個模塊都須要用到報表功能,一種方法是把報表功能作成一個單獨的組件,而後讓三個模塊都引用這個組件,計算操做由三個模塊各自進行;另外一種方法是把報表功能作成單獨的服務,讓這三個模塊直接使用這個服務來獲取數據,全部的計算操做都在一處進行,很明顯後者的方案會比前者好得多。

服務不只能對內提供還能對外提供,若是其餘合做夥伴須要使用咱們的報表服務,咱們又不想直接把全部的信息都公開給它們。在這種狀況下組件方式就不是很合理了,經過公開服務並對服務的使用方作受權和驗證,那麼咱們既能保證合做夥伴能獲得他們須要的數據,又能保證核心的數據不公開。

2          架構 分佈式的系統架構,主要從如下幾個方面來考慮:分層、面向服務以及分佈式數據庫。

2.1        分層模型 通常地,咱們將應用程序功能分爲三個方面,對應3層架構模式。它們是數據層、中間層(業務邏輯層)和表示層,以下圖所示。

1)        數據層:存儲數據以及從數據庫中得到較爲原始的數據。

2)        業務邏輯層:介於數據層和表示層之間,負責處理來自數據存儲或發送給數據存儲的數據,把數據轉換成符合商務規則的有意義的信息。

3)        表示層:從業務邏輯層得到信息並顯示給用戶,負責與用戶的交互。

 

 三層架構模式,將業務邏輯和數據存儲分離,並分別用獨立的服務器來承載,有利於分散系統的壓力。其優勢具體以下所示:

1)        由於客戶機不包含業務邏輯,因此它們變得更加簡潔。這就使部署和維護工做更加容易,由於更新業務邏輯只須要對應用服務器進行操做。

2)        客戶機與數據庫細節相分離。應用服務器可以與幾個不一樣的數據源(分佈在不一樣的數據庫服務器上,下文中會對分佈式數據庫系統進行介紹)協同工做,而且只對客戶機提供單一的訪問點。

3)        若是設計正確,業務邏輯就可以被分佈到幾個負載均衡的應用服務器上。若是用戶需求增長,則能夠添加更多的服務器以知足要求。同時,能夠將業務邏輯發佈爲服務,供客戶端應用程序或者其它服務調用,構建成面向服務的系統架構。

2.2        面向服務 一家汽車租賃公司決定建立一個新的應用程序,用於汽車預約。該租車預約應用程序的建立者知道,應用程序所實現的業務邏輯必須可以讓公司內外運行的其它軟件訪問。所以,他們決定以面向服務的方式來建立此應用程序,並經過定義完善的一組服務,將此應用程序的邏輯公開給其餘軟件。

爲了實現這些服務並使之與其餘軟件進行通訊,這一新應用程序將使用 .Net Framework的分佈式計算技術,主要有:

1)        ASP.NET Web 服務

它使用Soap交互信息,是跨平臺,跨語言的,目前大多數平臺都支持基本的 Web 服務,因此在 WCF 發佈以前,這是實現跨供應商互操做性的最直接的方法。通常用在B/S結構的系統中,須要IIS進行啓動。

下圖演示了客戶機消費Web服務的情形。客戶機能夠是一個Web應用程序、另外一個Web服務等。       Web服務的消費者調用名爲Method()的Web服務上的方法。實際調用向下層傳播,做爲Soap消息經過網絡,並向上層傳播到Web服務。Web服務執行並響應(若是有的話)。實現Web服務與客戶機之間的雙向通知或者發佈/訂閱功能是可能的,可是必須手工完成。客戶機能夠實現本身的Web服務並在對服務器的調用中傳遞該Web服務的引用。服務器能夠保存引用,而後回調給客戶機。

2)        .NET Remoting

專門爲緊密耦合的 .NET 到 .NET 通訊而設計,它爲本地網絡中的應用程序提供了無縫而直接的開發體驗。通常用在C/S結構的系統中,須要經過一個WinForm或是Windows服務進行啓動。

3)        Microsoft 消息隊列 (MSMQ)

提供持久穩定的消息傳送,這一般是間歇式鏈接的應用程序的最佳解決方案。這些應用程序對數據傳送、工做量分離以及應用程序生存期均要求有保證。

4)        WCF服務

WCF是使用託管代碼創建和運行面向服務的應用程序的統一架構,是開發者能夠創建一個跨平臺(可與在J2EE 服務器構建、非 Windows 系統上運行的應用程序通訊)、安全、可信賴、事務性的解決方案,能與目前已有的分佈式系統兼容。它是微軟分佈式應用程序開發的集大成者,整合了.Net 平臺下全部和分佈式系統有關的技術。

 

以通訊範圍而言,WCF能夠跨進程(同一機器上不一樣的應用程序之間的通訊)、跨子網、企業網(局域網內不一樣的機器之間的通訊)甚至於Internet(互聯網中不一樣的機器之間的通訊)。從宿主程序而言,能夠是ASP.NET,EXE , WPF(Windows Presentation Foundation), Windows Forms, NT Service, COM+.

2.3        分佈式數據庫系統 分佈式數據庫系統由分佈於多個計算機結點上的若干個數據庫系統組成,它提供有效的存取手段來操縱這些結點上的子數據庫。分佈式數據庫在使用上可視爲一個完整的數據庫,而實際上它是分佈在地理分散的各個結點上。分佈式數據庫系統適合於單位分散的部門,容許各個部門將其經常使用的數據存儲在本地,實施就地存放本地使用,從而提升響應速度,下降通訊費用。它有如下優勢:

1)        解決組織機構分散而數據須要相互聯繫的問題。好比銀行系統,總行與各分行處於不一樣的城市或城市中的各個地區,在業務上它們須要處理各自的數據,也須要彼此之間的交換和處理,這就須要分佈式的系統。

2)        均衡負載。負載在各處理機間分擔,可避免臨界瓶頸。

3)        可靠性高。數據分佈在不一樣場地,且存有多個副本,即便個別場地發生故障,不致引發整個系統的癱瘓。

4)        可擴充性好。當須要增長新的相對自主的組織單位時,可在對當前機構影響最小的狀況下進行擴充。

5)        提升系統性能系統。能夠根據距離選擇離用戶最近的數據副本進行操做,減小通訊代價,改善整個系統的性能。

分佈式數據庫系統雖然有諸多優勢,但它同時也帶來了許多新問題。如:數據一致性問題、更新同步以及查詢分解等的複雜性、數據遠程傳遞的實現、通訊開銷的下降等,這使得分佈式數據庫系統的開發變得較爲複雜。

3          總結 分佈式應用程序的開發,要對應用程序進行分層,各層之間相互獨立,經過服務或接口來進行調用,不只便於開發的管理,也有利於集成其餘平臺上的應用程序,實現了功能模塊的複用、重用,提升了應用程序的可擴展性。在業務數據量多的狀況下,還要考慮構建分佈式的數據庫系統,這能夠經過DBMS自動管理的數據訂閱、分發技術實現數據庫的數據同步,以達到數據共享的目的;也能夠與一些分佈式的計算技術結合起來,好比說.NET Remoting技術來解決各數據庫之間的通訊問題,等等。

針對大型的網站應用,分佈式部署策略能夠從如下幾個方面考慮:

1)        代理服務器實現請求的分離 。

2)        緩存的分佈式部署,提升系統性能。

3)        拆分網站的對外功能,例如不一樣域名前、後綴,URL 重寫。

4)        面向服務,每一個服務分佈到一臺服務器上 。

5)        數據庫的分佈式集羣部署。

6)        設立專門的應用服務器。好比發送郵件通知的服務。

 

EntityFramework Core依賴注入上下文方式不一樣形成內存泄漏了解一下?

 

前言

這個問題從未碰見過,是一位前輩問我EF Core內存泄漏問題時我纔去深刻探討這個問題,剛開始我比較驚訝,竟然還有這種問題,而後就有了本文,直接拿前輩的示例代碼並稍加修改爲就了此文,但願對在自學EF Core過程當中的童鞋能有些許幫助。

EntityFramework Core內存泄漏回顧

接下來我將用簡單示例代碼來還原整個形成EntityFramework Core內存泄漏的過程,同時在這個過程當中您也可思考一下其中的緣由和最終的結果是否一致。

    public class TestA
    {
        public long Id { get; set; }
        public string Name { get; set; }
    }
複製代碼
    public class EFCoreDbContext : DbContext
    {
        public EFCoreDbContext(DbContextOptions options)
            : base(options)
        {
        }
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer("data source=WANGPENG;User Id=sa;Pwd=sa123;initial catalog=MemoryLeak;integrated security=True;MultipleActiveResultSets=True;");
            base.OnConfiguring(optionsBuilder);
        }

        public DbSet<TestA> TestA { get; set; }
    }
複製代碼
複製代碼
    public class TestUserCase
    {
        public void InvokeMethod(IServiceProvider serviceProvider)
        {
            EFCoreDbContext _context = null;

            if (_context == null)
            {
                _context = serviceProvider.GetRequiredService<EFCoreDbContext>();
            }

            for (var i = 0; i < 10; i++)
            {
                var testA = _context.TestA.FirstOrDefault();
                Console.WriteLine(i);
            }
        }
    }
複製代碼

如上是整個示例代碼,重頭戲來了,接下來咱們在控制檯中來經過依賴注入上下文,並獲取注入容器中的上下文並調用上述TestUserCase類中的方法,以下:

複製代碼
            var services = new ServiceCollection();

            services.AddDbContext<EFCoreDbContext>(options => options.UseSqlServer("data source=WANGPENG;User Id=sa;Pwd=sa123;initial catalog=MemoryLeak;integrated security=True;MultipleActiveResultSets=True;"));

            var serviceProvider = services.BuildServiceProvider();

            for (int i = 0; i < 1000; i++)
            {
                var test = new TestUserCase();
                test.InvokeMethod(serviceProvider);
            }
複製代碼

 

經過上述測試內存基本在15兆左右,固然根據機器配置不一樣最終獲得的結果有所差別,可是內存基本沒有什麼大的波動,接下來咱們來改造上述代碼。上述咱們將serviceProvider經過方法傳遞到TestUserCase中的InvokeMethod方法中,爲了簡便咱們將獲取到的serviceProvider改形成靜態的,以下:

複製代碼
    public static class ServiceLocator
    {
        private static IServiceCollection _services;

        public static IServiceProvider Instance
        {
            get
            {
                if (_services == null)
                    return null;
                else
                    return _services.BuildServiceProvider();
            }
        }

        public static void Init(IServiceCollection services)
        {
            _services = services;
        }
    }
複製代碼
複製代碼
    public class TestUserCase
    {
        public void InvokeMethod()
        {
            IServiceScope _serviceScope = null;
            EFCoreDbContext _context = null;
            if (_context == null)
            {
                _serviceScope = ServiceLocator.Instance.GetRequiredService<IServiceScopeFactory>().CreateScope();
                _context = _serviceScope.ServiceProvider.GetRequiredService<EFCoreDbContext>();
            }

            for (var i = 0; i < 10; i++)
            {
                var testA = _context.TestA.FirstOrDefault();
                Console.WriteLine(i);
            }
        }
    }
複製代碼
複製代碼
            var services = new ServiceCollection();

            services.AddDbContext<EFCoreDbContext>(options => options.UseSqlServer("data source=WANGPENG;User Id=sa;Pwd=sa123;initial catalog=MemoryLeak;integrated security=True;MultipleActiveResultSets=True;"));

            ServiceLocator.Init(services);

            for (int i = 0; i < 1000; i++)
            {
                var test = new TestUserCase();
                test.InvokeMethod();
            }
複製代碼

如上咱們經過ServiceLocator類來構建serviceProvider,並將返回serviceProvider賦值給靜態變量,而後在咱們調用的方法中直接獲取容器中的上下文,這樣就免去了傳遞的麻煩。

通過咱們上述改造後最終運行內存達到了比較可怕的三百多兆,看來上下文壓根就沒進行GC,那我是否是改形成以下就能夠了呢?

複製代碼
            var scopeFactory = ServiceLocator.Instance.GetRequiredService<IServiceScopeFactory>();

            using (var scope = scopeFactory.CreateScope())
            using (var context = scope.ServiceProvider.GetRequiredService<EFCoreDbContext>())
            {
                for (var i = 0; i < 10; i++)
                {
                    var testA = context.TestA.FirstOrDefault();
                    Console.WriteLine(i);
                }
            }
複製代碼

 

原覺得是上下文沒有及時獲得釋放而致使內存激增,可是看到上述結果依然同樣沒有任何改變,問題是否是到此就結束了呢?下面咱們改變注入上下文的方式看看,以下:

複製代碼
            var services = new ServiceCollection();

            var options = new DbContextOptionsBuilder<EFCoreDbContext>()
              .UseSqlServer("data source=WANGPENG;User Id=sa;Pwd=sa123;initial catalog=MemoryLeak;integrated security=True;MultipleActiveResultSets=True;")
              .Options;
            services.AddScoped(s => new EFCoreDbContext(options));
複製代碼

當咱們改變了注入上下文方式後發現此時不會形成內存泄漏,也就是說上下文獲得了GC,不管是我是不是手動釋放上下文即經過Using包括或者不包括都不會出現內存泄漏問題。經過注入方式不一樣獲得的結果大相徑庭,可是在咱們的理解中經過AddDbContext注入上下文中的第二個參數是默認爲Scope,那和咱們經過AddScoped注入上下文應該是同樣對不對,那爲什麼結果又不一樣呢?豈不是衝突了嗎?在Web不會出現這樣的問題,未深刻研究,我猜想其緣由可能以下:

經過AddDbContext注入上下文只適用於Web應用程序即只對Web應用程序有效而對控制檯程序可能無效,同時在Web應用程序中AddDbContext注入上下文和AddScoped注入上下文一致,而對於控制檯程序存在不一致問題。一言以蔽之,在Web和Console中經過AddDbContext注入上下文可能存在處理機制不一樣。

總結

不知如上淺薄分析是否有漏洞或者說代碼有錯誤的地方,期待看到本文的您能有更深刻的看法可留下您的評論,若是結果是這樣不建議在控制檯中使用AddDbContext方法注入上下文。

 

SQL Server之深刻理解STUFF

 

前言

最近項目不管查詢報表仍是其餘數據都在和SQL Server數據庫打交道,對於STUFF也有了解,可是發現當下一次再寫SQL語句時我還得查看相關具體用法,說到底仍是沒有徹底理解其原理,因此本節咱們來談談STUFF,Jeff是在項目中哪裏不熟悉,哪裏不會或者哪裏耗時比較多就會去深刻理解和鞏固即便是很基礎的知識,直到徹底不用浪費時間去查閱相關資料,這是個人出發點。

深刻理解STUFF

STUFF字符串函數是將字符串插入到另外一個字符串中。它會刪除開始位置第一個字符串中的指定長度的字符,而後將第二個字符串插入到開始位置的第一個字符串中,語法以下。

STUFF(<character_expression>,<開始>,<長度>,<character_expression>)
<character_expression>參數是給定的字符串數據,能夠是字符或二進制數據的常量,變量或列。<start>參數是一個整數值,指定開始刪除和插入的位置,能夠是BIGINT類型。若是<開始>或<長度>參數爲負數,則返回NULL字符串。若是<start>參數比第一個<character_expression>長,則返回一個NULL字符串。 <length>參數能夠是BIGINT類型,它是一個整數,指定要刪除的字符數。若是<length>比第一個<character_expression>長,則刪除發生到最後一個<character_expression>中的最後一個字符。

複製代碼
DECLARE @FullName       VARCHAR(100)
DECLARE @Alias          VARCHAR(20)

SET @FullName = 'Jeffcky Wang'
SET @Alias = ' "Superman" '

SELECT STUFF(@FullName, CHARINDEX(' ', @FullName), 1, @Alias) AS [FullName]
複製代碼

 

如上STUFF函數中的第一個參數咱們給定的是@FullName,第二個是開始的位置,咱們經過CHARINDEX函數找出@FullName以空格隔開的的位置返回,最後由@Alias來代替,結果如圖所示。

DECLARE @Time VARCHAR(10)
SET @Time = '1030'

SELECT STUFF(@Time, 3, 0, ':') AS [HH:MM]

咱們給定的字符串爲@Time即1030,咱們從第3個位置開始,刪除長度爲0,此時則在3前面插入冒號,結果如上圖輸出10:30。

DECLARE @CreditCardNumber  VARCHAR(20)
SET @CreditCardNumber = '370200199408103544'

SELECT STUFF(@CreditCardNumber, LEN(@CreditCardNumber) -3, 4,
       'XXXX') AS [Output]

如上咱們將身份證經過STUFF將最後四位用XXXX代替。以上是STUFF最基礎的用法。STUFF最多見的用途莫過於結合FOR XML PATH對返回JSON字符串的拼接。首先利用FOR XML PATH則返回XML格式的字符串,咱們將FOR XML PATH添加到查詢的末尾,此時容許咱們將查詢的結果做爲XML元素輸出,元素名稱包含在PATH參數中。。

SELECT TOP 5 ',' + Name 
              FROM  Production.Product
              FOR XML PATH ('')

,Adjustable Race,All-Purpose Bike Stand,AWC Logo Cap,BB Ball Bearing,Bearing Ball

此時咱們利用STUFF將上述利用FOR XML PATH生成的字符串中的前置逗號去掉,以下:

SELECT Name = STUFF((
            SELECT TOP 5 ',' + NAME
            FROM Production.Product
            FOR XML PATH('')
            ), 1, 1, '')

好比咱們要查詢各類產品中的產品列表名稱,最後咱們改形成以下:

複製代碼
SELECT TOP 5 p2.ProductID, Name = STUFF((
            SELECT ',' + NAME
            FROM Production.Product AS p1
            WHERE p1.ProductID = p2.ProductID
            FOR XML PATH('')
            ), 1, 1, '') FROM Production.Product AS p2
GROUP BY p2.ProductID
複製代碼

接下來咱們利用STUFF結合FOR XML PATH來拼接JSON字符串,以下:

複製代碼
DECLARE @content VARCHAR(MAX)

SET @content = (SELECT '['+ STUFF((SELECT TOP 5 ',{"ProductName": "' + ProductName + '","Price": "' + CONVERT(VARCHAR, Price) + '","Quantity": "' + CONVERT(VARCHAR, quantity) + '","Inserton": "' + CONVERT(VARCHAR, Inserton, 105) + '"}' FROM ProductList 
 FOR XML PATH('')), 1, 1,''
 ) 
 + ']'[ProductDetail])

PRINT @content
複製代碼

結果如上正確輸出JSON字符串,接下來咱們將如上拼接換行再試試。

複製代碼
DECLARE @content VARCHAR(MAX)

SET @content = ( SELECT '['
                        + STUFF(( SELECT TOP 5
                                            ',{"ProductName": "' + ProductName
                                            + '","Price": "'
                                            + CONVERT(VARCHAR, Price)
                                            + '","Quantity": "'
                                            + CONVERT(VARCHAR, quantity)
                                            + '","Inserton": "'
                                            + CONVERT(VARCHAR, Inserton, 105)
                                            + '"}'
                                  FROM      ProductList
                                FOR
                                  XML PATH('')
                                ), 1, 1, '') + ']' [ProductDetail]
               )

PRINT @content
複製代碼

如上是利用SQL Prompt直接格式化換行,結果依然正確輸出JSON字符串,咱們再來手動換行試試。

複製代碼
DECLARE @content VARCHAR(MAX)

SET @content = (SELECT 
'['+ STUFF((SELECT TOP 5 ',
{"ProductName": "' + ProductName 
+ '","Price": "' + CONVERT(VARCHAR, Price) 
+ '","Quantity": "' + CONVERT(VARCHAR, quantity) 
+ '","Inserton": "' + CONVERT(VARCHAR, Inserton, 105) 
+ '"}' FROM ProductList 
 FOR XML PATH('')), 1, 1,''
 ) 
 + ']'[ProductDetail])

PRINT @content
複製代碼

結果輸出如上咱們不指望的字符串,主要是由FOR XML PATH形成的,好比咱們利用FOR XML PATH進行以下查詢:

SELECT  '    '
FOR     XML PATH('') 

當咱們利用FOR XML  PATH查詢數據時,若是字符串中包含空格時會形成出現以如上錯誤的字符串來填充,因此此時咱們爲了消除這種錯誤格式,咱們將上述繼續添加參數。

SELECT  '    '
FOR     XML PATH(''),TYPE 

此時咱們將上述輸出JSON字符串不錯誤的格式修改爲以下便可:

複製代碼
DECLARE @content VARCHAR(MAX)

SET @content = (SELECT 
'['+ STUFF((SELECT TOP 5 ',
{"ProductName": "' + ProductName 
+ '","Price": "' + CONVERT(VARCHAR, Price) 
+ '","Quantity": "' + CONVERT(VARCHAR, quantity) 
+ '","Inserton": "' + CONVERT(VARCHAR, Inserton, 105) + '"}' FROM ProductList 
 FOR XML PATH('') ,TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1,''
 ) 
 + ']'[ProductDetail])

PRINT @content
複製代碼

或者咱們對上述輸出的錯誤字符串進行替換,以下:

複製代碼
select t.PK, 
    ltrim(rtrim(replace(
    (select ' ' + isnull(ti.Column1, '') + ' ' + isnull(ti.Column2, '')
     from yourTable ti 
     where ti.PK = t.PK
     for xml path (''))
     , '&#x20;', ''))) fruits
from yourTable t
group by t.PK;
複製代碼

這裏咱們解決了利用STUFF有可能輸出JSON字符串帶有錯誤的字符串的問題,在利用STUFF輸出JSON字符串時只要有一列數據包含NULL,那麼返回的數據則爲空,那麼咱們在對列數據經過ISNULL來進行判斷,好比以下將輸出NULL。

複製代碼
DECLARE @content VARCHAR(MAX)

SET @content = (SELECT 
'['+ STUFF((SELECT TOP 5 ',
{"ProductName": "' + NULL 
+ '","Price": "' + CONVERT(VARCHAR, Price) 
+ '","Quantity": "' + CONVERT(VARCHAR, quantity) 
+ '","Inserton": "' + CONVERT(VARCHAR, Inserton, 105) + '"}' FROM ProductList 
 FOR XML PATH('') ,TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1,''
 ) 
 + ']'[ProductDetail])

PRINT @content
複製代碼

因此此時咱們必須經過ISNULL來判斷列數據是否爲NULL,修改爲以下形式:

複製代碼
DECLARE @content VARCHAR(MAX)

SET @content = (SELECT 
'['+ STUFF((SELECT TOP 5 ',
{"ProductName": "' + ISNULL(ProductName,'') 
+ '","Price": "' + CONVERT(VARCHAR, Price) 
+ '","Quantity": "' + CONVERT(VARCHAR, quantity) 
+ '","Inserton": "' + CONVERT(VARCHAR, Inserton, 105) + '"}' FROM ProductList 
 FOR XML PATH('') ,TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1,''
 ) 
 + ']'[ProductDetail])

PRINT @content



你必須知道的EntityFramework 6.x和EntityFramework Core變動追蹤狀態

 

前言

只要有時間就會時不時去看最新EF Core的進展狀況,同時也會去看下基礎,把握好基礎相當重要,本節咱們對比看看如標題EF 6.x和EF Core的不一樣,但願對正在學習EF Core的同行能有所幫助,同時也但願經過本文能對您心中可能產生的疑惑進行解答,本文略長,請耐心閱讀。

深刻探討EF 6.x和EF Core變動追蹤狀態話題

請注意雖然EF 6.x和EF Core在使用方式上沒有什麼不一樣,可是內置實現卻有所不一樣,瞭解它們的不一樣很重要,同時也但願更多同行選擇EF Core,EF 6.x使人詬病毋庸置疑,在使用上不了解基本知識就會出很大的問題,這一點我已經明確闡述過,EF Core爲咱們作了許多,只是咱們並未知道而已,看完本文相信您會認同我說的這句話,爲了便於你們理解咱們用實例來講明。

EntityState狀態設置和使用對應方法是否匹配?

不管是在EntityFramework 6.x仍是EntityFramework Core中DbSet上始終包含有Add、Attath、Remove等方法,當咱們調用Add方法來添加對象時,此時內部則是將對象狀態置爲添加狀態(Add),若是咱們調用Remove方法刪除對象,內部則是將對象置爲刪除狀態(Deleted),在EF 6.x中沒有Update方法,如果更新全部列則是隻需將對象狀態修改成Modified,不管怎樣都是經過EntityState來根據咱們的操做來設置對象相應的狀態,下面咱們一塊兒來看下例子。

複製代碼
            using (var ctx = new EfDbContext())
            {
                var customer = new Customer() { Id = 1, Name = "Jeffcky" };

                ctx.Entry(customer).State = EntityState.Modified;

                ctx.Customers.Add(customer);

                var state = ctx.Entry(customer).State;

                var result = ctx.SaveChanges();
            };
複製代碼

如上示例是在EF 6.x中,咱們首先實例化一個customer,而後將其狀態修改成Modified,最後咱們調用Add方法添加到上下文中,此時咱們獲得customer的狀態會是怎樣的呢?

沒毛病,對不對,最終調用Add方法其狀態將覆蓋咱們手動經過Entry設置的Modified狀態,接下來咱們將如上經過Entry方法修改成以下:

  ctx.Entry(customer).State = EntityState.Unchanged;

若是咱們這樣作了,結果固然也是好使的,那要是咱們繼續修改成以下形式呢?

複製代碼
            using (var ctx = new EfDbContext())
            {
                var customer = new Customer() { Id = 1, Name = "Jeffcky" };

                ctx.Entry(customer).State = EntityState.Deleted;

                ctx.Customers.Add(customer);

                var state = ctx.Entry(customer).State;

                var result = ctx.SaveChanges();
            };
複製代碼

結果仍是Added狀態,依然好使,咱們繼續進行以下修改。

複製代碼
            using (var ctx = new EfDbContext())
            {
                var customer = new Customer() { Id = 1, Name = "Jeffcky" };

                ctx.Entry(customer).State = EntityState.Added;

                ctx.Customers.Attach(customer);

                var state = ctx.Entry(customer).State;

                var result = ctx.SaveChanges();
            };
複製代碼

恩,仍是沒問題,這裏咱們能夠得出咱們經過Entry方法手動設置未被跟蹤對象的狀態後,最後狀態會被最終調用的方法所覆蓋,一切都是明朗,還沒徹底結束。那接下來咱們添加導航屬性看看呢?

複製代碼
            using (var ctx = new EfDbContext())
            {
                var customer = new Customer() { Id = 1, Name = "Jeffcky" };
                var order = new Order() { Id = 1, CustomerId = 1 };
                customer.Orders.Add(order);

                ctx.Entry(order).State = EntityState.Modified;

                ctx.Customers.Attach(customer);

                var state = ctx.Entry(order).State;

                var result = ctx.SaveChanges();
            };
複製代碼

反觀上述代碼,咱們實例化customer和order對象,並將order添加到customer導航屬性中,接下來咱們將order狀態修改成Modified,最後調用Attath方法附加customer,根據咱們上述對單個對象的結論,此時order狀態理論上應該是Unchanged,可是真的是這樣?

和咱們所指望的截然相反,此時經過調用attach方法並未將咱們手動經過Entry方法設置狀態爲Modified覆蓋,換言之此時形成了對象狀態不一致問題,這是EF 6.x的問題,接下來咱們再來看一種狀況,你會發現此時會拋出異常,拋出的異常我也看不懂,也不知道它想表達啥意思(在EF Core中不會出現這樣的狀況,我就不佔用一一篇幅說明,您可自行實踐)。

複製代碼
            using (var ctx = new EfDbContext())
            {
                var customer = new Customer() { Id = 1, Name = "Jeffcky" };
                var order = new Order() { Id = 1 };
                customer.Orders.Add(order);

                ctx.Entry(order).State = EntityState.Deleted;

                ctx.Customers.Attach(customer);

                var state = ctx.Entry(order).State;

                var result = ctx.SaveChanges();
            };
複製代碼

由上咱們得出什麼結論呢?在EF 6.x中使用Entry設置對象狀態和調用方法對相關的對象影響將出現不一致的狀況,接下來咱們來對比EF 6.x和EF Core在使用上的區別,對此咱們會有深入的理解,若是咱們還沿襲EF 6.x那一套,你會發現竟然很差使,首先咱們來看EF 6.x例子。

複製代碼
            using (var ctx = new EfDbContext())
            {
                var customer = new Customer()
                {
                    Name = "Jeffcky",
                    Email = "2752154844@qq.com",
                    Orders = new List<Order>()
                    {
                        new Order()
                        {
                            Code = "order",
                            CreatedTime = DateTime.Now,
                            ModifiedTime = DateTime.Now,
                            Price = 100,
                            Quantity = 10
                        }
                    }
                };
                ctx.Customers.Add(customer);
                var result = ctx.SaveChanges();
            };
複製代碼

這裏須要說明的是我將customer和order是配置了一對多的關係,從如上例子也可看出,咱們調用SaveChanges方法毫無疑問會將customer和order插入到數據庫表中,以下:

接下來咱們手動經過Entry方法設置customer狀態爲Added,再來看看,以下:

複製代碼
            using (var ctx = new EfDbContext())
            {
                var customer = new Customer()
                {
                    Name = "Jeffcky",
                    Email = "2752154844@qq.com",
                    Orders = new List<Order>()
                    {
                        new Order()
                        {
                            Code = "order",
                            CreatedTime = DateTime.Now,
                            ModifiedTime = DateTime.Now,
                            Price = 100,
                            Quantity = 10
                        }
                    }
                };
                ctx.Entry(customer).State = EntityState.Added;
                var result = ctx.SaveChanges();
            };
複製代碼

對照如上咱們再來看看在EF Core中是如何處理的呢?直接調用Add方法就不浪費時間演示了,用過EF Core的都知道必然好使,咱們看看手動設置狀態。

複製代碼
        public static void Main(string[] args)
        {
            using (var context = new EFCoreDbContext())
            {
                var blog = GetBlog();
                var post = new Post()
                {
                    CommentCount = 10,
                    CreatedTime = DateTime.Now,
                    ModifiedTime = DateTime.Now,
                    Name = "Jeffcky"
                };
                context.Entry(blog).State = EntityState.Added;
                var result = context.SaveChanges();
            }
            Console.ReadKey();
        }
        static Blog GetBlog()
        {
            return new Blog()
            {
                IsDeleted = false,
                CreatedTime = DateTime.Now,
                ModifiedTime = DateTime.Now,
                Name = "Jeffcky",
                Status = 0,
                Url = "http://www.blogs/com/createmyself"
            };
        }
複製代碼

經過實踐證實此時不會將Post添加到表中,爲何會如此呢?由於咱們只是手動設置了blog的狀態爲Added,而未對Post進行設置,看到這裏想必您知道了EF 6.x和EF Core的不一樣。EF團隊之因此這麼作的目的在於如EF 6.x同樣手動設置根對象的狀態其導航屬性即相應關聯的對象也會設置,這樣作會形成混亂,當咱們添加對象時其導航屬性也會對應添加,雖然看起來很天然,也適應一些狀況,可是對象模型並不清楚主體和依賴關係,因此在EF Core中則發生了改變,經過Entry方法只會對傳入對象的狀態有所影響而對關聯的對象不會發生任何改變,這點尤爲重要,咱們在使用EF Core時要格外注意,額外多說一句在EF Core經過Entry().State這個APi設置狀態只會對單個對象產生影響不會對關聯對象產生任何影響即忽略關聯對象。 

EntityFramework Core爲何在上下文中添加對應方法?

不知道使用過EF Core的您有沒有發現,在EF 6.x中咱們發如今上下文中並無如暴露的DbSet上的方法好比Add、AddRange、Remove、RemoveRange等等,可是在EF Core則存在對應的方法,不知道您發現過沒有,我雖然發現,可是一直不明白爲什麼如此這樣作,這樣作的目的在哪裏呢?我還特地看了EF Core實現源碼,結果發現其內部好像仍是調用了暴露在DbSet上的方法,若是我沒記錯的話,這樣不是畫蛇添足,吃飽了撐着了嗎,有這個時間實現這樣一個玩意,那怎麼不早早實現經過Incude進行過濾數據呢?EF Core團隊在github上討論當前這不是優先級比較高的特性,其實否則,不少時候咱們須要經過導航屬性來篩選數據,少了這一步,咱們只能加載到內存中再進行過濾。好了回到話題,我也是偶然看到一篇文章,才發現這樣設計的目的何在,接下來咱們首先來看看在EF 6.x中的上下文中沒有對應的方法結果形成的影響是怎樣的呢?經過實例咱們一看便知。

複製代碼
            using (var ctx = new EfDbContext())
            {
                var order = ctx.Orders.FirstOrDefault();
                var newOrder = new Order()
                {
                    CustomerId = order.CustomerId,
                    CreatedTime = DateTime.Now,
                    ModifiedTime = DateTime.Now,
                    Code = "addOrder",
                    Price = 200,
                    Quantity = 1000
                };
                ctx.Orders.Add(newOrder);
                var result = ctx.SaveChanges();
            };
複製代碼

特地給出如上表中數據來進行對比,如上代碼咱們查詢出第一個Order即上圖標註,而後咱們從新實例化一個Order進行添加,此時您能想象到會發生什麼嗎?瞧瞧吧。

結果是添加到表中了,可是可是可是,重要的事情說三遍,仔細看看數據和咱們要添加的Order數據對照看看,萬萬沒想到,此時獲得的數據是主鍵等於1的數據也就是舊數據。讓咱們再次回到EF Core中演示上述例子。

複製代碼
            using (var context = new EFCoreDbContext())
            {
                var post = context.Posts.FirstOrDefault();
                var newPost = new Post()
                {
                    CreatedTime = Convert.ToDateTime("2018-06-01"),
                    ModifiedTime = Convert.ToDateTime("2018-06-01"),
                    Name = "《你必須掌握的Entity Framework 6.x與Core 2.0》書籍出版",
                    CommentCount = 0,
                    BlogId = post.BlogId 
                };
                context.Add(newPost);
                var result = context.SaveChanges();
            }
複製代碼

如上代碼從新實例化一個Blog並添加到表中數據和如上圖中數據徹底不同,咱們經過上下文中暴露的Add方法來添加Blog,咱們來看看最終在表中的數據是怎樣的呢?

在EF Core上下文中有了Add,Attach、Remove方法以及Update和四個相關的Range方法(AddRange等等)和暴露在DbSet上的方法同樣。 同時在上下文中的方法更加聰明瞭。 它們如今能夠肯定類型並自動將實體對象關聯到咱們想要的的DbSet。不能說很方便,而是很是方便,由於它容許咱們編寫通用代碼而徹底不須要再實例化DbSet,固然咱們也能夠這樣作,只不過如今又多了一條康莊大道罷了,代碼簡易且易於發現。 

即便是以下動態對象,EF Core也能正確關聯到對應的對象,您親自實踐便知。

複製代碼
            using (var context = new EFCoreDbContext())
            {
                dynamic newBlog = new Blog()
                {
                    IsDeleted = true,
                    CreatedTime = Convert.ToDateTime("2018-06-01"),
                    ModifiedTime = Convert.ToDateTime("2018-06-01"),
                    Name = "《你必須掌握的Entity Framework 6.x與Core 2.0》書籍出版",
                    Status = 0,
                    Url = "http://www.cnblogs.com/CreateMyself/p/8655069.html"
                };
                context.Add(newBlog);
                var result = context.SaveChanges();
            }
複製代碼

讓咱們再來看看一種狀況來對比EF 6.x和EF Core在使用方式上的不一樣,首先咱們來看看EF 6.x例子:

複製代碼
            using (var ctx = new EfDbContext())
            {
                var customer = ctx.Customers.Include(d => d.Orders).FirstOrDefault();
                var newOrder = new Order()
                {
                    CreatedTime = DateTime.Now,
                    ModifiedTime = DateTime.Now,
                    Code = "addOrder",
                    Price = 200,
                    Quantity = 1000,
                    CustomerId = customer.Id
                };
                ctx.Orders.Attach(newOrder);  
                var result = ctx.SaveChanges();
            };
複製代碼

此時咱們可以看到咱們只是經過Attatch方法附加了newOrder,而後進行經過SaveChanges進行提交,此時並未提交到數據庫表中,那EF Core處理機制是否是也同樣呢?咱們來看看:

複製代碼
            using (var context = new EFCoreDbContext())
            {
                var blog = context.Blogs.FirstOrDefault();
                var newPost = new Post()
                {
                    CreatedTime = Convert.ToDateTime("2018-06-01"),
                    ModifiedTime = Convert.ToDateTime("2018-06-01"),
                    Name = "《你必須掌握的Entity Framework 6.x與Core 2.0》書籍出版",
                    CommentCount = 0,
                    BlogId = blog.Id
                };
                context.Attach(newPost);
                var result = context.SaveChanges();
            }
複製代碼

很驚訝是否是,在EF Core最終添加到數據庫表中了,依照咱們對EF 6.x的理解,經過Attach方法只是將實體對象狀態修改成Unchanged,若是咱們想添加對象那麼必須調用Add方法,此時對象狀態將變爲Added狀態,也就是說在EF 6.x中若是咱們調用Attatch方法,可是須要將對象添加到數據庫表中,此時必需要調用Add方法,反之若是咱們調用Add方法,那麼調用Attath方法附加對象則畫蛇添足,可是在EF Core中這種狀況經過上述演示很顯然發生了改變。那麼EF Core內部是根據什麼來判斷的呢?咱們來看以下源代碼:

經過上述源代碼不難看出在EF Core對於未設置主鍵都將視爲添加換句話說則是若是調用Attach方法附加一個未被跟蹤的對象時且主鍵值未被填充時,EF Core將其視爲添加,因此若是咱們須要添加對象時此時可直接調用Attach而無需調用Add方法。若是您依然不信,您可自行進行以下測試,也一樣會被添加到表中。

複製代碼
        public static void Main(string[] args)
        {
            using (var context = new EFCoreDbContext())
            {
                var blog = GetBlog();
                context.Attach(blog);
                var result = context.SaveChanges();
            }
            Console.ReadKey();
        }
        static Blog GetBlog()
        {
            return new Blog()
            {
                IsDeleted = false,
                CreatedTime = DateTime.Now,
                ModifiedTime = DateTime.Now,
                Name = "Jeffcky",
                Status = 0,
                Url = "http://www.blogs/com/createmyself"
            };
        }
複製代碼

EF Core團隊這麼作的目的是什麼呢?大部分狀況下經過調用Attach方法將可抵達圖中全部未跟蹤實體的狀態設置爲Unchanged,除非實體對象的主鍵咱們沒有設置且正在使用值生成,對於更新/修改同理。很顯然 這對許多斷開鏈接的實體的常見狀況很是有用。可是,在許多狀況下它不起做用,由於在特殊狀況下是根實體,即便咱們未設置主鍵也強制它的狀態保持不變,這樣作顯然不合理。若是咱們經過未設置主鍵調用Attach並最終添加它,這被認爲是意外行爲,咱們須要放開對根實體的特殊封裝,經過調用Attach方法來改變這種行爲,這會使得Attach變得更加適用,它並非突破性的改變。

Jeff自問自答模式來了,那麼咱們是否容許咱們屢次調用Attach來附加實體對象呢?您以爲是否可行呢?咱們來驗證下:

複製代碼
            using (var context = new EFCoreDbContext())
            {
                var blog = GetBlog();
                context.Attach(blog);
                context.Attach(blog);
                var result = context.SaveChanges();
            }
複製代碼

EntityFramework Core爲何添加無鏈接跟蹤圖(Disconnected TrackGraph)?

追蹤圖是EF中全新的概念,它提供了咱們對對象狀態的徹底控制,TrackGraph遍歷圖(即遍歷圖中的每一個對象)並將指定的函數應用於每一個對象。 該函數是TrackGraph方法的第二個參數。此特性的出現也是爲了調用對應方法和手動設置狀態而形成的混亂而給。好比咱們想實現如EF 6.x同樣,當調用Attach方法時不添加實體,那麼咱們能夠以下這樣作。

複製代碼
            using (var context = new EFCoreDbContext())
            {
                var blog = GetBlog();
                context.ChangeTracker.TrackGraph(blog, node =>
                {
                    if (!node.Entry.IsKeySet)
                    {
                        node.Entry.State = EntityState.Unchanged;
                    }
                });
                context.Attach(blog);
                var result = context.SaveChanges();
            }
複製代碼

總結

本文咱們詳細講解了EF 6.x和EF Core在實體狀態上使用方式的不一樣且講解了咱們須要注意到兩者的不一樣,接下來咱們會繼續回顧基礎,感謝您的閱讀,咱們下節再會。

修正

關於本文用EF 6.x添加數據出現舊數據問題是我寫的代碼有問題,特此致歉,不知道是在什麼場景會產生舊數據的問題,以前確實看過一篇文章,可是示例忘記了。

相關文章
相關標籤/搜索