分類
發燒車訊

越野旅遊收益因疫情銳減 保育經費無以為繼

摘錄自2020年6月24日公視報導

非洲國家受到疫情衝擊,各國野生動物保育專案計畫的經費也被迫裁減。保育團體就擔心,盜獵象牙和犀牛角的惡習,將和疫情一起蔓延。

根據非洲的旅行業同業公會估計,從肯亞、烏干達一路往南,到波札那和南非,這類搭車跟著野生動物觀察遷徙路線的行程,每年可以帶來總計約新台幣3670多億元的收益。但因疫情國際航空幾乎停擺,經調查顯示,超過300家大小旅行社,有9成以上業者的業績只剩原來的1/4。除了相關的產業收入銳減,有關各國的野生動物保育專案計畫也被迫裁減編制與經費。

由於中國在2018年以維護文化傳統、充實中醫藥材為由,取消買賣犀牛角的禁令,保育團體擔心盜獵者將利用巡邏人力的缺口,把非法取得的犀牛角拿去賺黑心錢。路透社的報導指出,南非有三個頗受歡迎、又可合法狩獵的野生動物公園,採取防範措施。工作人員在讓犀牛得以存活的條件下,切除部份的犀牛角,希望減少盜獵者對這些犀牛的興趣。

生物多樣性
國際新聞
非洲
武漢肺炎
象牙
犀牛角
動物與大環境變遷

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※超省錢租車方案

※別再煩惱如何寫文案,掌握八大原則!

※回頭車貨運收費標準

※教你寫出一流的銷售文案?

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

網頁設計最專業,超強功能平台可客製化

分類
發燒車訊

委內瑞拉燃油短缺 單車通勤成生活新常態

摘錄自2020年6月19日公視報導

全球儲油量第一的委內瑞拉,卻因為美國加強禁運和經濟制裁,國內陷入石油危機,民眾排隊加油竟然要等上三天三夜,也促使許多人開始改以自行車代步。

在委內瑞拉,石油長年比水還便宜,民眾大多開車上班,現在因為沒油可買,許多民眾轉而騎單車通勤。自行車技師塞古拉表示:「修理自行車的量變多了,我計算至少多出20至30倍」

該地煉油設備老舊到不堪使用,過去以原油和俄羅斯交換燃油,如今交易也因為受到美國制裁而停擺,面臨歷年來最嚴重的汽油短缺,更有民眾說,沒油可用比新冠病毒更讓人苦惱。

現在委內瑞拉最低月薪3塊美金左右,台幣不到100塊,等於只夠買六公升左右的汽油,無疑是生活一大負擔,也難怪騎單車通勤,成了越來越多委內瑞拉民眾生活的新常態。

生活環境
能源議題
能源轉型
國際新聞
委內瑞拉
單車
自行車
石油危機
石油
交通運輸

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※回頭車貨運收費標準

※推薦評價好的iphone維修中心

※超省錢租車方案

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

※推薦台中搬家公司優質服務,可到府估價

分類
發燒車訊

地球第六次大滅絕正在加速 研究:500種野生動物將在20年內消失

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

※教你寫出一流的銷售文案?

※超省錢租車方案

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※回頭車貨運收費標準

分類
發燒車訊

風力發電機噪音 芬蘭研究:「次聲波」不影響健康

摘錄自2020年6月23日自由時報

根據《Science alert》報導,根據研究人員的說法,因為許多國家的民眾把頭痛、噁心、耳鳴和心血管疾病等症狀,都歸咎於次聲波,所以研究團隊接受芬蘭政府的委託,耗時2年研究次聲波對於人體的影響。

研究人員期間透過訪談、錄音和實驗室實驗等方式,試圖找出風力發電機的次聲波,是否會影響周圍20公尺範圍內的居民健康。

研究人員表示,結果皆無法證實上述假設,影響健康的因素反而跟「預期症狀」(symptom expectancy)等有關。值得注意的是,研究團隊也沒有發現風力發電機的聲音會影響心律的證據。

能源議題
再生能源
能源轉型
國際新聞
芬蘭
風力發電
噪音

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※別再煩惱如何寫文案,掌握八大原則!

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※超省錢租車方案

※教你寫出一流的銷售文案?

網頁設計最專業,超強功能平台可客製化

※產品缺大量曝光嗎?你需要的是一流包裝設計!

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

分類
發燒車訊

Amazon設立20億美元氣候承諾基金

摘錄自2020年6月24日iThome報導

Amazon在23日宣布設立氣候承諾基金(The Climate Pledge Fund),初期將以20億美元的資金來推動各種能夠符合「氣候承諾」的技術與服務。

Amazon與Global Optimism在去年9月共同發起「氣候承諾」(Climate Pledge),計畫在2040年實現淨零碳(net zero carbon),比《巴黎協議》(Paris Agreement)訂定的2050年目標還早了10年。

Amazon創辦人暨執行長貝佐斯(Jeff Bezos)表示,氣候承諾基金將會投資那些有願景的企業家與創新者,讓他們建置能協助企業減少碳排放影響、而且能持久經營的產品及服務。該基金的投資對象涵蓋各個領域,從運輸、能源、儲存、製造與材料、循環經濟,到食物及農業。

此外,Amazon也揭露了目前該公司對於改善氣候變遷的成效,表示可能會提前5年,於2025年達到全數使用再生能源的目標。

能源議題
再生能源
能源轉型
國際新聞
亞馬遜
氣候基金

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※教你寫出一流的銷售文案?

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※回頭車貨運收費標準

※別再煩惱如何寫文案,掌握八大原則!

※超省錢租車方案

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※推薦台中搬家公司優質服務,可到府估價

分類
發燒車訊

俄羅斯西伯利亞飆高溫 北極圈小鎮38度破紀錄

摘錄自2020年6月22日中央社報導

根據氣象數據網站的資料顯示,過去曾出現零下68°C極端低溫的俄羅斯西伯利亞小鎮維爾霍揚斯克(Verkhoyansk),竟在昨天(21日)測得38°C高溫。

美聯社報導,彙整俄羅斯氣象數據網站Pogoda i Klimat的資料指出,維爾霍揚斯克鎮20日高溫達到38°C。

俄羅斯薩哈共和國(Sakha Republic)的維爾霍揚斯克鎮在北極圈內,位於首都莫斯科(Moscow)東北方大約4660公里處。

全球變遷
溫室氣體
氣候變遷
國際新聞
北極
高溫

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※超省錢租車方案

※別再煩惱如何寫文案,掌握八大原則!

※回頭車貨運收費標準

※教你寫出一流的銷售文案?

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

網頁設計最專業,超強功能平台可客製化

分類
發燒車訊

英醫學權威警告政界 小心出現第二波疫情

摘錄自2020年6月24日中央廣播電台報導

路透社今天(24日)報導,資深醫界人士警告英國各政黨,當地俗稱武漢肺炎的2019年冠狀病毒疾病(COVID-19)疫情可能升溫,而且第二波疫情有實質風險。

這些醫學界人士在一封寫給英國政界領袖的公開信中說:「雖然這場疫情未來在英國的情勢難以預估,現有證據顯示,當地爆發疫情的可能性愈來愈大,而第二波(疫情)有實質風險。」

在「英國醫學期刊」(British Medical Journal, BMJ)上簽署這封公開信的人士,包含英國皇家外科醫學院(Royal College of Surgeons)院長奧德森(Derek Alderson)、皇家內科醫學院(Royal College of Physicians)院長戈達(Andrew Goddard),以及皇家緊急醫藥大學院長韓德森(Katherine Henderson)。

他們表示:「遏止病毒必備的許多基礎要素已準備就緒,但重大的挑戰依然存在。」

生活環境
國際新聞
英國
武漢肺炎
疫情
新冠肺炎疫情
公共衛生

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※回頭車貨運收費標準

※推薦評價好的iphone維修中心

※超省錢租車方案

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

※推薦台中搬家公司優質服務,可到府估價

分類
發燒車訊

悅翔V7的小弟,據說比大哥操控還棒!

動力總成悅翔V3搭載了1。4L自然吸氣發動機+5擋手動變速箱,最大輸出101匹馬力和135牛米。實際表現來看,悅翔V3不同於一般小排量的車會把油門調得較為靈敏,它反而會調得偏肉,起步並不是很利索,但是3擋以下提速還是很給力的,只是滿載時會較為吃力,上個緩坡也不是很帶勁。

一說起長安,大家首先想到的肯定是CS75。但是除了SUV車型以外,長安還有一些不錯的小車,例如悅翔V3。可能有少部分讀者聽過這台車,那其產品力到底如何呢?

大哥悅翔V7已經獲得不少人的認可,但是小弟悅翔V3基本處於默默無聞的狀態。其實,悅翔V3的整個設計還是有點小V7的感覺。

長安汽車-悅翔V3

指導價:4.69-5.39萬

外觀設計

悅翔V3的車身尺寸為4200*1650*1465mm,軸距為2410mm。前臉來看,跟悅翔V7差別不大。發動機艙蓋上的兩條弧線剛強有力,兩顆大燈也顯得炯炯有神,中網上的鍍鉻裝飾條,點綴得剛好,不顯俗氣。

側面的話,車身還是顯得比較緊湊,只是尾部看起來會有點臃腫。同時輪胎的尺寸也偏小了一點。

相比起車頭,尾部會顯得有點平庸,僅有車牌上方的鍍鉻裝飾條略微點綴一下。

內飾設計

車廂的用料在這個價位來說算是可以的,中控台的設計中規中矩。烤黑鋼琴漆的面板算是為數不多的亮點所在。三副式的方向盤上面沒有任何按鈕,看起來很乾凈,樣式也不錯,給人感覺很好。

動力總成

悅翔V3搭載了1.4L自然吸氣發動機+5擋手動變速箱,最大輸出101匹馬力和135牛米。實際表現來看,悅翔V3不同於一般小排量的車會把油門調得較為靈敏,它反而會調得偏肉,起步並不是很利索,但是3擋以下提速還是很給力的,只是滿載時會較為吃力,上個緩坡也不是很帶勁。

底盤表現

悅翔V3的前懸架為麥弗遜式獨立懸架,而後懸架則為多連桿獨立懸架。這在同級別車型中是比較罕見的。實際表現來看,底盤的調校較為偏向於操控,過彎時的側傾不大。但是面對顛簸時會有種硬碰硬的感覺。

空間表現

受制於2410mm的軸距,後排空間並不充裕。身高為182cm的體驗者坐於後排,腿部僅有4指的空間,而頭部則僅為三指。雖然後排中央的拱起不高而且平整,但是受制於偏短的腿部空間,坐於後排中部的乘客也只能稍微將就一下。

油耗表現

多位車主反映的悅翔V3百公里綜合油耗為6.2L,這個数字是相當省的,也是許多車主購買它的原因。

配置分析

悅翔V3隻有三個車型可以選擇,但是每個車型又分國四與國五版本,中間價差1000元。這三個車型中,我會推薦中配的手動溫馨型,它比低配的手動美滿型貴了3000元,但是卻多出了主副駕駛座的安全氣囊和后駐車雷達。這兩項配置都很重要,儘管車子本身便宜,但是這種關乎生命安全的配置還是不能省。

編者總結:

悅翔V3可以說一直活在大哥悅翔V7的陰影下,同時受制於自身定位的問題,在市場上的表現也較為一般,但同級罕有的後輪獨立懸架賦予了它同級出色的操控性。如果是一台個人用車的話,悅翔V3可以滿足你對操控的幻想。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案

※回頭車貨運收費標準

分類
發燒車訊

沒了IDE,你的Java項目還能Run起來嗎~

計算機只能識別機器碼0101…編程語言->能執行的機器碼 需要經過 預處理->編譯->彙編->鏈接->機器碼過程。一個語言處理系統的示意圖如下:

編譯器 是將源語言程序一次性翻譯成一個等價的,用目標語言編寫的程序。還存在另一種常見的語言處理器,解釋器:它是逐個語句的執行源語言程序。由一個編譯器產生的目標語言程序通常比一個解釋器快,但解釋器的錯誤診斷效果通常更好。

Java語言處理器結合了編譯和解釋的過程。一個.Java源程序首先被編譯為.class字節碼文件,被加載到虛擬機中,然後由虛擬機將字節碼翻譯成機器碼。

虛擬機的好處在於:一旦一個程序被轉換成 Java 字節碼,那麼它便可以在不同平台上的虛擬機實現里運行。實現一次編寫,到處運行。另外一個好處是它帶來了一個託管環境。這個託管環境能夠代替我們處理一些代碼中冗長而且容易出錯的部分,如自動內存管理與垃圾回收。

在Hotspot中,虛擬機翻譯字節碼有兩種方式:

1.解釋執行
即逐條將字節碼翻譯成機器碼並執行。

2.即時編譯
即將一個方法中包含的所有字節碼編譯成機器碼后再執行。

前者的優勢在於無需等待編譯,而後者的優勢在於實際運行速度更快。HotSpot 默認採用混合模式,綜合了解釋執行和即時編譯兩者的優點。它會先解釋執行字節碼,而後將其中反覆執行的熱點代碼,以方法為單位進行即時編譯。

即時編譯建立在程序符合二八定律的假設上,也就是百分之二十的代碼佔據了百分之八十的計算資源。

好了,裝X結束。

阿姨知道的編譯知識全在上面了。。(っ╥╯﹏╰╥c)

如題,下面我們來看一下讓Java項目運行起來我們能做什麼。

我們能做的很簡單,當然不是寫虛擬機。我們只需要:

1.執行command javac,將.Java文件變為.class文件。
2.執行command java,讓.class文件運行起來。

也就是 執行command :)

Java程序的運行方式

Java程序可以通過java命令運行.class文件運行可執行Jar文件
我們先看第一種方式:從Hello World開始。

運行.class文件

Step1:編寫Java文件

Step2:執行 command javac

將.Java文件變為.class文件

小貼士:class文件的全路徑名是包名目錄+ 類文件名。

Step3:執行 command java

運行.class文件

神奇,我們沒有用IDE讓Java程序運行起來了 :)

小夥伴先別噴老阿姨,哪特么有這麼簡單的Java項目啊。。我們工作中用的明明都是Jar文件啊…
Jar文件咋運行啊!!

運行可執行Jar文件

Jar文件是基於ZIP文件格式的一種文件格式,它將大量的Java類文件、相關的元數據和資源(文本、圖片等)文件聚合到一個Jar文件中,此外還包含一個可選的META-INF文件夾。這個文件夾下的文件或文件夾主要用來打包和擴展配置信息,包括安全,版本,擴展程序和服務等。如MANIFEST.MF文件定義了擴展和打包的相關數據信息。
一個Jar文件通常在項目中用作第三方類庫使用,也是項目構建的一部分。

生成一個Jar文件大致分為兩步:

1.將源文件編譯為.class文件

2.通過 command jar命令將.class文件,資源文件等等打成一個文件格式的Jar文件。

我們以一個SbDemo項目為例來看Jar文件的打包和運行。項目目錄結構如下:

Test2.java中調用了Test1.java的方法,

我們需要先將Test1.java編譯並打成一個Test1.jar文件,然後通過Test1.jar將Test2.java編譯並打成一個可執行的Test2.jar文件

可執行和不可執行的Jar文件 區別在於是否在Jar文件中指定了main方法的入口,我們後面再看。

Step1:Test1.java的編譯

Step2:將編譯后的classes/com/Test1.class文件打成一個Test1.jar包

Java中和jar包相關的命令是jar命令,生成一個jar包我們需要定義信息文件(manifest-file),它可以定義所生成jar包的classpath類搜索路徑,jar包的入口類等等。可以理解為與Jar包相關的元數據配置信息
Step2.1 書寫信息文件
這裏我們使用resources/manifest-test1.text文件作為信息文件

是的,Test1.java太簡單了,就是打成一個可被他人引用的jar包,信息文件不重要。
Step2.2 執行打包命令

Step3. 編譯Test2.java文件
因為Test2.java中引用了com.Test1類,所以我們需要在編譯時指定Classpath路徑。
Classpath:顧名思義,是指待編譯類依賴的類所在路徑位置。我們可以通過 javac 的 -cp 參數指定。
關於編譯時classpath的值優先級如下:

  • 如果沒有傳入classpath參數,將使用環境變量CLASSPATH的值。(小夥伴不知道環境變量咋查看和設置?去看阿姨的上一篇文章:)
  • 如果沒有發現環境變量CLASSPATH,將使用 執行命令的當前文件夾(.)。
  • 如果javac命令行 通過-classpath or -cp參數指定了類路徑值,則優先級最高。

這裏我們使用-cp指定Test1.jar所在位置

可以看到classes目錄下已經生成了com2/Test2.class文件了。

Step4. 將編譯后的Test2.class和它依賴的Test1.jar一起打成一個可執行的Jar包
Step4.1 書寫信息文件
這時候我們使用信息文件resources/manifest-test2.text文件指定這些信息

Step4.2 執行Jar包生成命令

可以看到在lib目錄下生成了Test2.jar

Step5.運行我們的可執行Jar

大功告成了,我們的SbDemo項目Run起來了…

當然實際項目不可能人肉編譯,打包。我們需要通過Maven/Gradle等構建工具,幫助我們管理代碼之間的Jar包依賴,構建,部署…我們可能大多時候通過點一下IDE就託管了Maven的構建部署命令。

拿Maven舉例子,Maven首先定義了一套項目結構,我們按照它的結構書寫代碼,引入各個模塊所需要的Jar包依賴。然後Maven可以通過自己的生命周期管理項目的清理,構建,打包,部署階段。每個階段有對應的Maven插件執行相應的目標。IDE又整合了Maven,使我們通過點吧點吧按鈕就完成了項目的運行。

但是當一個項目並沒有按照規範的構建工具結構搭建,或者項目沒有成功運行報錯時,了解Java實際的編譯運行過程會對理解、解決這類問題有所幫助。

好啦,限於篇幅,阿姨先不講這些年Maven躺過的坑了,有想看的嗎?關注,在看,轉發三連回應下 >-<

參考資料:
[1].《編譯原理》序 (゚´ω`゚)゚
[2].https://time.geekbang.org/column/article/11289

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

※教你寫出一流的銷售文案?

※超省錢租車方案

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※回頭車貨運收費標準

分類
發燒車訊

【asp.net core 系列】8 實戰之 利用 EF Core 完成數據操作層的實現

0. 前言

通過前兩篇,我們創建了一個項目,並規定了一個基本的數據層訪問接口。這一篇,我們將以EF Core為例演示一下數據層訪問接口如何實現,以及實現中需要注意的地方。

1. 添加EF Core

先在數據層實現層引入 EF Core:

cd Domain.Implements
dotnet add package Microsoft.EntityFrameworkCore

當前項目以SqlLite為例,所以再添加一個SqlLite數據庫驅動:

dotnet add package Microsoft.EntityFrameworkCore.SQLite

刪除 Domain.Implements 里默認的Class1.cs 文件,然後添加Insfrastructure目錄,創建一個 DefaultContext:

using Microsoft.EntityFrameworkCore;

namespace Domain.Implements.Insfrastructure
{
    public class DefaultContext : DbContext
    {
        private string ConnectStr { get; }
        public DefaultContext(string connectStr)
        {
            ConnectStr = connectStr;
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlite(ConnectStr);//如果需要別的數據庫,在這裏進行修改
        }
    }
}

2. EF Core 批量加載模型

通常情況下,在使用ORM的時候,我們不希望過度的使用特性來標註實體類。因為如果後期需要變更ORM或者出現其他變動的時候,使用特性來標註實體類的話,會導致遷移變得複雜。而且大部分ORM框架的特性都依賴於框架本身,並非是統一的特性結構,這樣就會造成一個後果:本來應該是對調用方隱藏的實現就會被公開,而且在項目引用關係中容易出現循環引用。

所以,我在開發中會尋找是否支持配置類,如果使用配置類或者在ORM框架中設置映射關係,那麼就可以保證數據層的純凈,也能實現對調用方隱藏實現。

EF Core的配置類我們在《C# 數據訪問系列》中關於EF的文章中介紹過,這裏就不做過多介紹了(沒來得及看的小夥伴們不着急,後續會有一個簡單版的介紹)。

通常情況下,配置類我也會放在Domain.Implements項目中。現在我給大家介紹一下如何快速批量加載配置類:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetAssembly(this.GetType()),
		t => t.GetInterfaces().Any(i => t.Name.Contains("IEntityTypeConfiguration")));
}

現在版本的EF Core支持通過Assembly加載配置類,可以指定加載當前上下文類所在的Assembly,然後篩選實現接口中包含IEntityTypeConfiguration的類即可。

3. 使用EF Core實現數據操作

我們已經創建好了一個EF Context,那麼現在就帶領大家一起看一下,如何使用EF來實現 上一篇《「asp.net core」7 實戰之 數據訪問層定義》中介紹的數據訪問接口:

新建一個BaseRepository類,在Domain.Implements項目的Insfrastructure 目錄下:

using Domain.Infrastructure;
using Microsoft.EntityFrameworkCore;

namespace Domain.Implements.Insfrastructure
{
    public abstract class BaseRepository<T> : ISearchRepository<T>, IModifyRepository<T> where T : class
    {
        public DbContext Context { get; }
        protected BaseRepository(DbContext context)
        {
            Context = context;
        }
    }
}

先創建以上內容,這裏給Repository傳參的時候,使用的是EFCore的默認Context類不是我們自己定義的。這是我個人習慣,實際上並沒有其他影響。主要是為了對實現類隱藏具體的EF 上下文實現類。

在實現各接口方法之前,創建如下屬性:

public DbSet<T> Set { get => Context.Set<T>(); }

這是EF操作數據的核心所在。

3.1 實現IModifyRepository接口

先實現修改接口:

public T Insert(T entity)
{   
    return Set.Add(entity).Entity;
}

public void Insert(params T[] entities)
{
    Set.AddRange(entities);
}

public void Insert(IEnumerable<T> entities)
{
    Set.AddRange(entities);
}
public void Update(T entity)
{
    Set.Update(entity);
}

public void Update(params T[] entities)
{
    Set.UpdateRange(entities);
}

public void Delete(T entity)
{
    Set.Remove(entity);
}

public void Delete(params T[] entities)
{
    Set.RemoveRange(entities);
}

在修改接口裡,我預留了幾個方法沒有實現,因為這幾個方法使用EF Core自身可以實現,但實現會比較麻煩,所以這裏藉助一個EF Core的插件:

dotnet add package Z.EntityFramework.Plus.EFCore

這是一個免費開源的插件,可以直接使用。在Domain.Implements 中添加后,在BaseRepository 中添加如下引用:

using System.Linq;
using System.Linq.Expressions;

實現方法:

public void Update(Expression<Func<T, bool>> predicate, Expression<Func<T, T>> updator)
{
    Set.Where(predicate).UpdateFromQuery(updator);
}

public void Delete(Expression<Func<T, bool>> predicate)
{
    Set.Where(predicate).DeleteFromQuery();
}

public void DeleteByKey(object key)
{
    Delete(Set.Find(key));
}

public void DeleteByKeys(params object[] keys)
{
    foreach (var k in keys)
    {
        DeleteByKey(k);
    }
}

這裏根據主鍵刪除的方法有個問題,我們無法根據條件進行刪除,實際上如果約定泛型T是BaseEntity的子類,我們可以獲取到主鍵,但是這樣又會引入另一個泛型,為了避免引入多個泛型根據主鍵的刪除就採用了這種方式。

3.2 實現ISearchRepository 接口

獲取數據以及基礎統計接口:

public T Get(object key)
{
    return Set.Find(key);
}

public T Get(Expression<Func<T, bool>> predicate)
{
    return Set.SingleOrDefault(predicate);
}

public int Count()
{
    return Set.Count();
}

public long LongCount()
{
    return Set.LongCount();
}

public int Count(Expression<Func<T, bool>> predicate)
{
    return Set.Count(predicate);
}

public long LongCount(Expression<Func<T, bool>> predicate)
{
    return Set.LongCount(predicate);
}

public bool IsExists(Expression<Func<T, bool>> predicate)
{
    return Set.Any(predicate);
}

這裡有一個需要關注的地方,在使用條件查詢單個數據的時候,我使用了SingleOrDefault而不是FirstOrDefault。這是因為我在這裏做了規定,如果使用條件查詢,調用方應該能預期所使用條件是能查詢出最多一條數據的。不過,這裏可以根據實際業務需要修改方法:

  • Single 返回單個數據,如果數據大於1或者等於0,則拋出異常
  • SingleOrDefault 返回單個數據,如果結果集沒有數據,則返回null,如果多於1,則拋出異常
  • First 返回結果集的第一個元素,如果結果集沒有數據,則拋出異常
  • FirstOrDefault 返回結果集的第一個元素,如果沒有元素則返回null

實現查詢方法:

public List<T> Search()
{
    return Query().ToList();
}

public List<T> Search(Expression<Func<T, bool>> predicate)
{
    return Query(predicate).ToList();
}

public IEnumerable<T> Query()
{
    return Set;
}

public IEnumerable<T> Query(Expression<Func<T, bool>> predicate)
{
    return Set.Where(predicate);
}

public List<T> Search<P>(Expression<Func<T, bool>> predicate, Expression<Func<T, P>> order)
{
    return Search(predicate, order, false);
}

public List<T> Search<P>(Expression<Func<T, bool>> predicate, Expression<Func<T, P>> order, bool isDesc)
{
    var source = Set.Where(predicate);
    if (isDesc)
    {
        source = source.OrderByDescending(order);
    }
    else
    {
        source = source.OrderBy(order);
    }
    return source.ToList();
}

這裏我盡量通過調用了參數最多的方法來實現查詢功能,這樣有一個好處,小夥伴們可以想一下哈。當然了,這是我自己覺得這樣會好一點。

實現分頁:

在實現分頁之前,我們知道當時我們定義的分頁參數類的排序字段用的是字符串,而不是lambda表達式,而Linq To EF需要一個Lambda表示才可以進行排序。這裏就有兩種方案,可以自己寫一個方法,實現字符串到Lambda表達式的轉換;第二種就是借用三方庫來實現,正好我們之前引用的EF Core增強插件里有這個功能:

var list = context.Customers.OrderByDescendingDynamic(x => "x.Name").ToList();

這是它給出的示例。

我們可以先依此來寫一份實現方法:

public PageModel<T> Search(PageCondition<T> condition)
{
    var result = new PageModel<T>
    {
        TotalCount = LongCount(condition.Predicate),
        CurrentPage = condition.CurrentPage,
        PerpageSize = condition.PerpageSize,
    };
    var source = Query(condition.Predicate);
    if (condition.Sort.ToUpper().StartsWith("a")) // asc
    {
        source = source.OrderByDynamic(t => $"t.{condition.OrderProperty}");
    }
    else // desc
    {
        source = source.OrderByDescendingDynamic(t => $"t.{condition.OrderProperty}");
    }
    var items = source.Skip((condition.CurrentPage -1)* condition.PerpageSize).Take(condition.PerpageSize);
    result.Items = items.ToList();
    return result;
}

回到第一種方案:

我們需要手動寫一個字符串的處理方法,先在Utils項目創建以下目錄:Extend>Lambda,並在目錄中添加一個ExtLinq類,代碼如下:

using System.Linq;
using System.Linq.Expressions;
using System.Text.RegularExpressions;

namespace Utils.Extend.Lambda
{
    public static class ExtLinq
    {
        public static IQueryable<T> CreateOrderExpression<T>(this IQueryable<T> source, string orderBy, string orderAsc)
        {
            if (string.IsNullOrEmpty(orderBy)|| string.IsNullOrEmpty(orderAsc)) return source;
            var isAsc = orderAsc.ToLower() == "asc";
            var _order = orderBy.Split(',');
            MethodCallExpression resultExp = null;
            foreach (var item in _order)
            {
                var orderPart = item;
                orderPart = Regex.Replace(orderPart, @"\s+", " ");
                var orderArry = orderPart.Split(' ');
                var orderField = orderArry[0];
                if (orderArry.Length == 2)
                {
                    isAsc = orderArry[1].ToUpper() == "ASC";
                }
                var parameter = Expression.Parameter(typeof(T), "t");
                var property = typeof(T).GetProperty(orderField);
                var propertyAccess = Expression.MakeMemberAccess(parameter, property);
                var orderByExp = Expression.Lambda(propertyAccess, parameter);
                resultExp = Expression.Call(typeof(Queryable), isAsc ? "OrderBy" : "OrderByDescending",
                    new[] {typeof(T), property.PropertyType},
                    source.Expression, Expression.Quote(orderByExp));
            }

            return resultExp == null
                ? source
                : source.Provider.CreateQuery<T>(resultExp);
        }
    }
}

暫時不用關心為什麼這樣寫,後續會為大家分析的。

然後回過頭來再實現我們的分頁,先添加Utils 到Domain.Implements項目中

cd ../Domain.Implements # 進入Domain.Implements 項目目錄
dotnet add reference ../Utils
public PageModel<T> Search(PageCondition<T> condition)
{
    var result = new PageModel<T>
    {
        TotalCount = LongCount(condition.Predicate),
        CurrentPage = condition.CurrentPage,
        PerpageSize = condition.PerpageSize,
    };
    var source = Set.Where(condition.Predicate).CreateOrderExpression(condition.OrderProperty, condition.Sort);
    var items = source.Skip((condition.CurrentPage -1)* condition.PerpageSize).Take(condition.PerpageSize);
    result.Items = items.ToList();
    return result;
}

記得添加引用:

using Utils.Extend.Lambda;

在做分頁的時候,因為前台傳入的參數大多都是字符串的排序字段,所以到後端需要進程字符串到字段的處理。這裏的處理利用了C# Expression的一個技術,這裏就不做過多介紹了。後續在.net core高級篇中會有介紹。

4. 總結

到目前為止,看起來我們已經成功實現了利用EF Core為我們達成 數據操作和查詢的目的。但是,別忘了EF Core需要手動調用一個SaveChanges方法。下一篇,我們將為大家介紹如何優雅的執行SaveChanges方法。

這一篇介紹到這裏,雖然說明不是很多,但是這也是我在開發中總結的經驗。

更多內容煩請關注我的博客《高先生小屋》

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※別再煩惱如何寫文案,掌握八大原則!

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※超省錢租車方案

※教你寫出一流的銷售文案?

網頁設計最專業,超強功能平台可客製化

※產品缺大量曝光嗎?你需要的是一流包裝設計!

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!