軟體開發(軟件開發)

網智數位主要提供套裝及客製化的軟體系統解決方案,專為客戶量身訂做客製化的軟體,達成客製化、智慧化及網路化的管理功能。

室內設計、裝潢、窗簾報價估算軟體

網智數位主要提供套裝及客製化的軟體系統解決方案,針對室內設計師、木工、裝潢業產業,量身訂做客製化的軟體,達成客製化、智慧化及網路化的商用軟體。

商用軟體-客製化設計

網智數位主要提供套裝及客製化的軟體系統解決方案,專為客戶量身訂做客製化的軟體,達成客製化、智慧化及網路化的管理功能。

IOT 物聯網-系統開發

根據客戶實際狀況,結合雲端與載具進行客製化物聯網IOT導入與軟體開發

雲端VPS虛擬主機租用

我們的雲端VPS虛擬主機是採用雲端(虛擬化)技術所開發之全新雲端伺服器服務,可以選擇多種作業系統(Windows、Linux等),客戶可載入自訂的應用環境,執行自己所要提供的網路服務,我們的雲端服務可為您的網站提供最完美的解決方案。

ERP軟體客製化導入

ERP軟體客製化導入,室內設計、營造業、裝潢、木作工程、系統櫃工程、會計系統,全面提升公司管理營運效率。

搜尋引擎最佳化SEO

搜尋引擎最佳化(SEO)不僅能提高網站在搜尋結果的排名,更能帶來大量對我們產品或服務真正有需求的訪客。SEO 最棒的特質之一就是不像廣告一樣亂槍打鳥而導致用戶的反感,反而更能提升點閱率跟成交率喔。

服務宗旨

網智數位主要提供套裝及客製化的軟體系統解決方案,專為客戶量身訂做客製化的軟體,達成客製化、智慧化及網路化的管理功能。

我們的成立宗旨就是要以最猛的IT技術讓這個世界更Smart,在我們貫徹我們裡想的同時,我們希望可以把我們所開發的系統帶給台灣的中小企業,除了要推薦好的東西之外,我們也希望做點改變,所以我們的第一目標就是要使用最好用的系統再加上您寶貴的創意,不僅僅可以節省你大量的荷包,還可以有一個像樣的網站。我們可以幫你做的有

企業管理
  • 策略管理
  • 目標管理
  • 行銷管理
  • 財會管理
  • ERP導入
  • 企業流程自訂
資訊管理
  • 網站架設
  • 虛擬化/雲端架設
  • 主機代管
  • 私有雲建制與導入
軟體開發
  • UML設計
  • 版本控管
  • 企業軟體開發
  • APP開發
  • 網頁設計
資訊安全
  • 網頁弱點掃描
  • 主機弱點掃描
  • 木馬檢測
  • 資安鑑識
  • 設計網路架構
  • 資安監控
行銷
  • 關鍵字SEO
  • 社群網路行銷
  • 部落格行銷
  • FaceBook 粉絲團
其他
  • 協助企業申請Google Email
好玩工具開發

講出你的創意吧!沒有甚麼是資訊辦不到的

顯示具有 .NET 標籤的文章。 顯示所有文章
顯示具有 .NET 標籤的文章。 顯示所有文章

2016年4月27日 星期三

優秀聰明的程式設計師必備的 5 種條件

       作為一個軟體開發人員在任何專案開發的系統架構與設計上起著非常關鍵的作用,而目前當前的現代化架構的開發趨勢下是需要更聰明、更有智慧的開發人員,這些開發人員具備了各種務實的技術能力。
下載
那麼究竟我們該如何定義這些聰明、有智慧的程式開發者呢?可以歸納有這樣 5 個主要關鍵因素:

1.有良好的專注力以及依目標為導向

      開始反思和規劃你的職業生涯。對你的程式碼,你比較也應該要實施如下:
保持模組化——個性化,專業化——這兩個方面都需要好好考慮,並且你的待辦事項需要定期整理。
保持清潔並遵守規則——我們需要遵循程式編碼規則以及自己制定的規則習慣,並且保持目標的乾淨和可衡量。
保持鬆耦合——不要將很多目標耦合到一起——保持簡單和靈活才能獨立地變化。
保持可衡量——保持目標基於SLA,並且每兩週/每月/每季度/每年衡量,越頻繁越好。

2.積極地推廣和行銷你的想法(Idea)

        這是最被忽略的一方面,也是最困難的一部分。你的想法需要告知他人才能被執行,而要實現這些目標,首要的是你必須將你的想法推廣和行銷給他人。
講故事是一個眾所周知的用一種每個人都可以理解的方法傳達思想的手段。
SapientNitro重新定義Storytelling到Storyscaping,這是一種新的講故事的方式,它連接了體驗(用於市場營銷)。這也可以用於普通的講故事中。

3.時時刻刻地提高工作效率

        不斷努力的思維過程以便於想出新的、好的可以改進的做事方式。一個簡單的例子就是——通過檢測早期問題,Jmeter腳本來做單位級別的性能測試和降低質量成本。
與團隊分享你的知識(博客或網絡會議的形式)。這有助於提高整個團隊的工作效率,也有機會得到別人的反饋。

4.通過學習跟上時代的腳步


通過閱讀來自於領先的高科技公司的博客(Netflix Tech Blog,Oracle OTN,AWS Blogs,IBM Emerging Tech Blog,DZone,TechGig,TechCrunch)
瀏覽高科技公司的開發者網站(如Facebook for Developers,Twitter Developers,Amazon AWS)
在問答網站提出問題(如Quora,Stackoverflow)
在MOOC網站(Coursera,Udemy等)或YouTube頻道學習
最後,通過以下關鍵技術人物/公司在社交媒體上的渠道(Twitter,LinkedIn等)。

5.必須維持好健康的頭腦、身體和心靈


這是最重要的一點,因為它能保持一個人的精氣神,確保我們有樂觀和健康的心態來應對任何挑戰,想出創新方法來做事情。
總而言之,這 5 個關鍵技能因素絕對可以協助我們在當前動態以及快速變化的資訊科技的技術中獲得更多的成功。

參考文章:5 Skills a Software Developer Should Have to Be a Smart Developer




網智數位-軟體開發(軟件開發)
針對各特殊產業都可以量身定做符合貴公司的需求,別人無法克服的就是我們的挑戰
業務合作、軟體委外開發
業務窗口:allen@netqna.com
聯繫行動號碼:0920-883-870
黃先生 Allen

2016年4月12日 星期二

.NET C# 7 語法 新特性 快速預覽 (軟體開發)

目前最新的 Visual Studio 15 發表的預覽版中,我們可以看出來,微軟決定為眾多的 .NET C# 開發人員,而新增了下列的 C# 7 語法新功能特色 。

元組值類型
.NET 提供了一個元組(Tuple)類型,但具體在 C# 中使用時卻存在著各種各樣的問題。由於元組類型是一個引用類型(Reference),而也因此在一些對於性能相當敏感的程式碼行中,開發者很可能會避免因使用它而造成 GC(Garbage Collection) 的開銷成本。同時,元組類型是不可變的,雖然這使跨線程( Thread) 共享變得更安全,但也意味著每次進行變更都必須分配一個新的對象。
下載

為了應對這一問題,C# 7 將提供一個值類型(Value)的元組。這是一個可變類型,對那些重視性能的程式碼來說,這種方式將更為高效。同時,作為值類型,它在每次進行分配時都會生成一個拷貝,因此幾乎沒有產生多線程(Multi-Thread) 問題的風險。
程式開發人員現在可以透過下列語法創建一個元組:
var result = (6, 20);
你也可以選擇對元組中的值進行命名,這一點並不是必須的,只是讓程式碼具有更好的可讀性。
var result = (count: 6 sum: 20);

你可能會想,“很棒的特性,但我自己也能寫得出來”。但下一個特性才是重頭戲。
多返回值,在類C風格的語言中,要在一個函數中返回兩個值始終是一件麻煩事。你只能選擇將結果封裝成某種結構,或是使用輸出參數。與許多函數式編程語言一樣,C#選擇了第一種方式為你提供這一特性:
(int, int) Tally (IEnumerable<int> list)

可以看到,在這裡使用泛用的元組有一個基本問題:我們將無從得知每個字段的作用。因此,C#選擇通過一個編譯器花招對結果進行命名:
(int Count, int Sum) Tally (IEnumerable<int> list)

我們在此需要強調一點:C#並沒有生成一個新的匿名類型,你所獲得的仍舊是一個元組,但編譯器將假設它的屬性為 Count 和 Sum,而不是 Item1 和 Item2。所以,以下程式碼行的作用都是等價的:

var result = Tally (list);
Console.WriteLine (result.Item1);
Console.WriteLine (result.Count);

請注意一點,我們現在還不具備多賦值語法,如果這種語法最終實現,那麼它的用法可能是這樣的:
(count, sum) = Tally (list);

除了提供簡單的功能性函數之外,多返回值的實用性還體現在非同步的程式碼的編寫上,因為在 async 函數中是不允許使用 out 參數的。
模式匹配:改進的 Switch 語法塊
VB 與函數式程序員對於 C# 抱怨得最多的一點就是 C# 中的 switch 語句功能十分有限。 VB 開發者希望能夠進行範圍匹配,而習慣了F#或 Haskell 的開發者則希望能夠使用分解式的模式匹配。 C#打算同時提供這兩種特性。

在對類型進行模式匹配時,你可以創建一個變量以保存轉型的結果。舉例來說,在對一個 System.Object 使用 switch 語句時,你可以編寫以下程式碼:
case int x:
如果該對像是數值類型,則變量x將得以賦值。否則的話,程序將按從上至下的順序檢查下一個 case 語句塊。如果你想更具體地進行匹配,還可以使用範圍檢查:
case int x when x > 0:
case int y:
在這個示例中,如果該對像是正整數,則x程式碼塊將被執行。如果對像是 0 或負整數,而y程式碼塊將被執行。
如果需要檢查 null 值,則只需使用以下語法:
case null;

模式匹配:分解
目前為止,我們僅僅展示了某種對 VB 中已有的特性所做的增量式改進,而模式匹配真正的強大之處在於分解,它可以將某個對象完全拆開,考慮一下以下語法:
if (person is Professor ​​{Subject is var s, FirstName is "Scott"})
這段程式碼完成了兩件事:
它創建了一個本地變量s,將其賦值為((Professor) person) .Subject。
它執行了一次相等性檢查 ((Professor) person) .FirstName == "Scott"。
如果將其用C# 6 程式碼改寫則是這樣:

var temp = person as Professor;
if (temp != null && temp.F​​irstName == "Scott")
{
    var s = temp.Subject

在最終發布中,我們預計能夠同時看到對 switch 語句塊的這兩種改進。
引用返回對於大數據結構進行引用傳遞比起值傳遞要快得多,因為後者需要對整個結構進行拷貝。與之類似,返回一個大數據結構的引用一樣能夠提升速度。
在類似於C這樣的語言中,可以通過指針返回某個結構的引用。這種方式會帶來一個常見的問題,即指針所指向的內存可能會因為某種原因而已經被回收了。
C#通過使用引用的方式迴避這一問題,引用本身是一個附加了規則的指針。最重要的一條規則是,你不能夠返回某個本地變量的引用。如果你嘗試這樣做,那麼該變量所引用的棧信息在函數返回時就已經變得不可訪問了。

在微軟的展示程式碼中,它所返回的引用指向一個數組中的某個結構。由於它實質上是指向數組中某個元素的指針,因此隨後可以對數組本身進行修改。舉例來說:

var x = ref FirstElement (myArray)
x = 5; //MyArray[0] now equals 5

這一語法的用例是對性能高度敏感的程式碼,在大多數應用中都無需使用這一特性。
二進製字面值(Binary Literals)
此次發布還引入了一個小特性,即二進製字面值。這一語法只是一個簡單的前綴而已,例如 5 可以表示為“0b0101”。這一特性的主要用例是設置基於 flag 的枚舉,以及創建位掩碼(bitmask),以用於與C風格語言的互操作。
本地函數
本地函數是指在另一個函數中所定義的函數。第一眼看來,本地函數似乎只是比匿名函數稍好的一種語法。但它實際上還存在幾個優點:
首先,你無需為其分配一個委託以保存該函數。這不僅減少了內存壓力,同時還允許編譯器對該函數進行內聯操作。
其次,在創建閉包時,也無需為其分配一個對象,因為它能夠直接訪問本地變量。這一點同樣能夠改善性能,因為它也減少了 GC 的壓力。
按照第二條規則推算,你將無法創建一個指向本地函數的委託。這一點對於程式碼的組織其實是一個優點,因為你無需創建獨立的函數,並且將現有函數的狀態作為顯式的參數進行傳遞。
部分類的改進
最後演示的特性是一種處理部分類的新方式。在過去,部分類的應用是基於程式碼生成優先的概念而出現的。所生成的會程式碼將包含一系列部分方法,開發者可以選擇實現這些方法,以調整類的行為。
通過新的“replace”語法,開發者就多了一種新選擇,能夠以最直接的方式編寫程式碼,隨後再引入程式碼生成器,並重寫這些方法。以下將通過一個簡單的示例表現開發者的程式碼編寫方式:
public string FirstName {get; set;}
簡單又清晰,但完全不符合 XAML 風格應用的寫法。因此,程式碼生成器將生成如下程式碼:
private string m_FirstName;
static readonly PropertyChangedEventArgs s_FirstName_EventArgs =new PropertyChangedEventArgs ("FirstName")
 
replace public string FirstName {
    get {
        return m_FirstName;
    }
    set {
        if (m_FirstName == value)
            return;
    m_FirstName = value;
    PropertyChanged?.Invoke (this, m_FirstName_EventArg);
}

通過“replace”關鍵字,所生成的程式碼將直接替換手寫的程式碼,添加所缺失的功能。在這個示例中,我們甚至還能夠處理一些開發者經常會忽略的麻煩的部分,例如對 EventArgs 對象進行緩存。
雖然這個官方示例僅用於屬性變更通知,但這一技術還可用於各種“面向切面編程(AOP)”的場景,例如在程式碼中的日誌記錄、安全檢查、參數校驗以及其他各種繁瑣的樣板式程式碼。

網智數位-軟體開發(軟件開發)
針對各特殊產業都可以量身定做符合貴公司的需求,別人無法克服的就是我們的挑戰
業務合作、軟體委外開發
業務窗口:allen@netqna.com
聯繫行動號碼:0920-883-870
黃先生 Allen

2016年3月30日 星期三

微軟收購 Xamarin 了,未來透過 Visual Studio 開發 Android & IOS APP

       微軟剛​​剛收購了一家熱門初創企業 Xamarin,這家初創企業主要幫助開發者編寫應用並將開發者編寫的作品投放到任何智能手機或操作系統之中。
      下載
       對微軟而言,收購Xamarin 有著重要的意義,因為在最近幾年中,微軟一直努力將更多的應用引入自己的Windows Store 應用市場之中——這也是微軟大力推行Windows 10 系統的重要舉措之一。
諸如 JetBlue 和 Coca-Cola Bottling 之類的客戶都使用 Xamarin 來節省大量的時間和金錢。開發者也不需要學雜費時間來為 iPhone、Android 或其它的任何系統重新編寫相同的應用,這些應用一旦編寫完成之後,往往都具有更大的生產效率。
微軟在將更多的 iPhone 和 Android 應用引入 Windows 10 方面面臨著較大的挑戰,為了解決這些問題,微軟已經大力投資技術,以此幫助開發者更加無縫地將他們的應用引入 Windows 之中。
Xamarin-Microsoft-1
Xamarin 當然非常支持微軟的這些舉措,同時也能夠讓微軟支持的大量開發者更加容易地利用他們的 .​​NET 和 C# 標準編寫程序代碼,並將他們的應用引入諸如 Android 和 iPhone 等平台之中。
微軟與 Xamarin 的歷史較為久遠,但雙方之間的關係曾經也飄忽不定:雙方曾經是長期的合作夥伴,與聯合客戶合作,並幫助他們打造應用,同時也給這些應用提供支撐。但是,曾有一段時間,微軟被認為是 Xamarin 業務的秘密投資方,因而早在 2014 年就有過一段傳聞,宣稱這一併購交易即將進行。
針對這一交易,微軟雲業務主管斯科特·古斯瑞(Scott Guthrie)表示,“通過今天宣布這一收購交易,我們將進一步推動這一工作,以便讓我們世界級的開發者工具和服務更好地進行深度整合,從而為開發者帶來無縫的移動應用開發體驗。”
2015 年底,Xamarin 與甲骨文簽署了一份協議,以此將開發者引入甲骨文云業務(Oracle Cloud)之中,而甲骨文云業務與微軟的 Azure 雲平台之間存在競爭關係。 Xamarin 與甲骨文的這份協議,或許是刺激微軟最終採取措施並完全收購 Xamarin 的重要原因。
從 Xamarin 的角度來看,該公司是一個非常成功的初創型企業,宣稱在全球擁有 1.5 萬家客戶。最近,BI 還將 Xamarin 定義為秘密運行互聯網的 9 家初創型企業之一。
與此同時,微軟在吸引開發者以便為全新的 Windows 10 操作系統打造應用方面也一直存在困難。通過收購 Xamarin,微軟如今也能夠為客戶提供全新且更加便捷的方式,從而更好地為 Windows 編寫應用,並通過微軟的 Azure 雲業務來支持這些應用。總而言之,對微軟而且,這一交易是一個非常重要的舉措。
另外,Xamarin 也提供所謂的測試雲產品,這一產品能夠讓開發者查看應用在各種設備的運行表現——包括在 Android、iPhone 和 BlackBerry 等設備上。如今,所有的這些業務都將整合到微軟的業務之中,這樣或將更能夠引開發者。
對微軟而言,最終的一大目標就是打造更大規模和更具吸引力的雲產品。隨著微軟與亞馬遜都在爭著吸引更多的客戶,因此,從這個角度而言,收購 Xamarin 對微軟將起著重要作用。另外,此次交易還將對 Windows 10 的應用戰略起到巨大的支撐作用。由此看來,收購 Xamarin 的確是微軟的一個明智抉擇。
來源:goo.gl/KUWbEQ1

網智數位-軟體開發(軟件開發)
針對各特殊產業都可以量身定做符合貴公司的需求,別人無法克服的就是我們的挑戰
業務合作、軟體委外開發
業務窗口:allen@netqna.com
聯繫行動號碼:0920-883-870
黃先生 Allen

2015年11月28日 星期六

Entity Framework 實戰 - 多對多自我關聯 Many to Many , Self Referencing 模型實作 (二)

此篇文是 Entity Framework 實戰 - 多對多自我關聯 Many to Many , Self Referencing 模型實作 (一)的續篇 , 當我們把基本模型 Product Class 建立好後,我們開始實作一個繼承 DbContext 的子類別,在這邊你可以把 DbContext 當做是資料庫的層次意義角度來看待
新增一個Class 名為 ProductContext.cs
image
然後按【新增】按鈕,並在 ProductContext 宣示繼承 DbContext 類別,如以下程式碼
  1: using System;
  2: using System.Collections.Generic;
  3: using System.Data.Entity;
  4: using System.Linq;
  5: using System.Text;
  6: using System.Threading.Tasks;
  7: 
  8: namespace EF6_ManyToManyAndSelf
  9: {
 10:     public class ProductContext : DbContext
 11:     {
 12: 
 13:     }
 14: }

接著加入 DbSet<Product> 的宣告,用於表示 存放著 Product Table(Class)的集合清單
public DbSet<Product> Products;
然後為了完成透過 Product 本身的 Class 來完成 多對多自身關聯,需要 override OnModelCreating Method , 程式碼如下

   1:   protected override void OnModelCreating(DbModelBuilder modelBuilder)
   2:          {
   3:              base.OnModelCreating(modelBuilder);
   4:   
   5:              modelBuilder.Entity<Product>()
   6:                          .HasMany(p => p.RelatedProducts)
   7:                          .WithMany(p => p.AboveProducts)
   8:                          .Map(m =>
   9:                                    {
  10:                                        m.MapLeftKey("ProductID");
  11:                                        m.MapRightKey("RelatedProductID");
  12:                                        m.ToTable("RelatedProduct");
  13:                                    }
  14:                          );
  15:          }

到這邊基本上已經完成 EntityFramework 的宣告….

然後讓我們在前端界面使用我們實作好的 ProductContext ,來看看如何使用….程式碼如下


   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Text;
   5:  using System.Threading.Tasks;
   6:   
   7:  namespace EF6_ManyToManyAndSelf
   8:  {
   9:      class Program
  10:      {
  11:          static void Main(string[] args)
  12:          {
  13:              using (var context = new ProductContext())
  14:              {
  15:                  var product1 = new Product { ProductName = "美容業零售管理系統", Price = 59888M };
  16:                  var product2 = new Product { ProductName = "窗簾業ERP系統", Price = 3500000M };
  17:                  var product3 = new Product { ProductName = "玩具製造業ERP系統", Price = 6700000M };
  18:                  product2.RelatedProducts.Add(product3);
  19:                  product1.RelatedProducts.Add(product2);
  20:                  context.Products.Add(product1);
  21:                  context.SaveChanges();
  22:              }
  23:              using (var context = new ProductContext())
  24:              {
  25:                  var product2 = context.Products.First(p => p.ProductName == "窗簾業ERP系統");
  26:                  Console.WriteLine("Product: {0} ... {1}", product2.ProductName, product2.Price.ToString("C"));
  27:                  Console.WriteLine("Related Products");
  28:                  foreach (var prod in product2.RelatedProducts)
  29:                  {
  30:                      Console.WriteLine("\t{0} ... {1}", prod.ProductName, prod.Price.ToString("C"));
  31:                  }
  32:                  foreach (var prod in product2.AboveProducts)
  33:                  {
  34:                      Console.WriteLine("\t{0} ... {1}", prod.ProductName, prod.Price.ToString("C"));
  35:                  }
  36:              }
  37:   
  38:              Console.ReadKey();
  39:          }
  40:      }
  41:  }


 
 



執行結果為


image





網智數位-軟體開發(軟件開發)

Entity Framework 實戰 - 多對多自我關聯 Many to Many , Self Referencing 模型實作 (一)

在我們軟體開發過程中,我們會遇到一種特殊模型實體關係,例如一個線上商品系統,會有產品資料表(Product Table),以及記錄產品的【相關產品】和該產品本身可以被關聯的上層【相關產品】,感覺很繞口,下圖我截取一個 ER-D 示例圖:
image
上圖ERD 關聯存在所謂的多對多關係 (Many to Many)而且又是自我關聯(自身關聯,Self Referencing),本身的主要邏輯是 RelatedProduct 這個Table,擔任一個用來記錄多對多關聯記錄的中繼Table,RelatedProduct Table包含了2個欄位(ProductID、RelatedProductID),2個欄位都是參考(Referencing)到 Product Table的 ProductID 主鍵值 ( Primary Key ),透過這樣的技巧可以表達一個產品可以關聯多個相關產品,反之也可以表達一個產品可以被多少產品有所關聯….
但現在我要教大家實作一個只需要在 Entity Framework 建立一個 Product Model (POCO),然後透過一些程式寫法技巧,來達成 這種商業資料模型  - 》 多對多自我關聯 Many to Many , Self Referencing 。
首先讓我們用 Visual Studio 開發工具來先新增一個程式專案,在此我程式專案命名為 EF6_ManyToManyAndSelf,然後按確定。
image
接下來,我們需要透過 NuGet來安裝 EntityFramework ,
image
image
在上圖執行安裝按鈕後,後續 NuGet 就會開始安裝 EntityFramewok , 目前 Allen 裝的版本為 6.1.3 穩定版,安裝過程可能會等候一點點時間,裝完後,你會發現專案的參考對了2個參考項目
image
確定沒問題後,接下來我們來新增一個 Product Class ,用來代表 Product table 的對應,完整程式碼如下:
image
   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.ComponentModel.DataAnnotations;
   4:  using System.ComponentModel.DataAnnotations.Schema;
   5:  using System.Linq;
   6:  using System.Text;
   7:  using System.Threading.Tasks;
   8:   
   9:  namespace EF6_ManyToManyAndSelf
  10:  {
  11:      [Table("Product", Schema = "dbo")]
  12:      public class Product
  13:      {
  14:          public Product()
  15:          {
  16:              RelatedProducts = new HashSet<Product>();
  17:              AboveProducts = new HashSet<Product>();
  18:          }
  19:   
  20:          [Key]
  21:          [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
  22:          public int ProductID { get; set; }
  23:   
  24:          public string ProductName { get; set; }
  25:   
  26:          public decimal Price { get; set; }
  27:   
  28:          /// <summary>
  29:          /// 記錄此產品的多個相關的產品
  30:          /// </summary>
  31:          public virtual ICollection<Product> RelatedProducts { get; set; }
  32:   
  33:          /// <summary>
  34:          /// 記錄此產品被那些上層產品標示為相關的產品
  35:          /// </summary>
  36:          public virtual ICollection<Product> AboveProducts { get; set; }
  37:   
  38:      }
  39:  }
 

    實作到這邊已經把基本的 EntityFramework 安裝進來,也把產品模型寫成一個POCO Class ,後續是更進階的 程式技巧已經背後運作解釋,請繼續參閱我撰寫  Entity Framework 實戰 - 多對多自我關聯 Many to Many , Self Referencing 模型實作 (二) 的介紹。



網智數位-軟體開發 (軟件開發)

2015年11月20日 星期五

微軟實際行動回歸開發者為中心擁抱全平台開發者

      微軟在今日舉辦的年度開發者大會上宣布了大量新款和升級後的開發者工具,包括了Visual Studio雲訂閱和全新Azure Service Fabric的預覽。為了賦予開發者更大的權力,微軟還介紹了全新免費且已即時上線的Visual Studio Dev Essentials項目。通過這項技術,開發者們將能夠在其喜歡的任何設備和任意系統上打造應用,從而減少其額外的投資成本。全程無尿點,全是亮點,就連開場都是一大亮點霍金的開場如同美國大片,使用面部表情控制電腦,進行交流,使用Visual studio 為霍金提供的全新交互方式:微軟在今日舉辦的年度開發者大會上宣布了大量新款和升級後的開發者工具,包括了Visual Studio雲訂閱和全新Azure Service Fabric的預覽。為了賦予開發者更大的權力,微軟還介紹了全新免費且已即時上線的Visual Studio Dev Essentials項目。通過這項技術,開發者們將能夠在其喜歡的任何設備和任意系統上打造應用,從而減少其額外的投資成本。全程無尿點,全是亮點,就連開場都是一大亮點霍金的開場如同美國大片,使用面部表情控制電腦,進行交流,使用Visual studio 為霍金提供的全新交互方式:






一、發布.NET Core RC和 ASP.Net RC
一年前的2014年11月,Connect(); 為開源開發者開啟了一段新的旅程- 宣布了.NET Core開源,以及可以在Linux, Mac OS 以及Windows 操作系統上運行的Visual Studio Code,這也標誌著微軟在開放和開源的道路上邁出了堅實的一步。昨晚微軟同時升級了.Net Core 和ASP.Net,開發者可以開始在生產環境使用微軟開源的.Net Core 跨平台框架和ASP.Net Web 平台。
微軟發布了.Net Core 5 和ASP.Net 5 的RC 版本,支持Linux,Windows 和Mac OS X 平台,這兩個軟件在一年前就已經開源了。 .Net Core 現在主要是從數據中心擴展到觸摸屏設備,添加了CoreCLR runtime 和CoreFX 庫,主要是由ASP.Net 工作流驅動。
最重要的是.NET Core 和ASP.Net 添加'go live' 協議,允許用戶在生長環境部署,可以反饋在生產環境是如何運作的。並且,現在.Net Core 已經完全支持Mac,Linux 和Windows 三個平台,特性都已完整。 .Net Core 還新增了大量APIs,包括key ones for localization 和networking。 ASP.Net v5 修改了hosting model,所以可以持續跨平台,支持Mac,Linux 和Windows。
自從開源了.Net Core,微軟還提供了其他開源的技術,包括CLR 和NuGet 包技術,還包括之前開源的Roslyn 編譯器項目。上個月微軟還宣布了與Red Hat 的合作,這些都說明,微軟已經走上了全新的開源之路!
二、開源Visual Studio Code 跨平台編輯器
微軟今天正式開源Visual Studio Code 跨平台編輯器,支持Mac,Linux 和Windows 平台。微軟同時還發布了VS Code v0.10.1 Beta 版本,最重要的是Visual Studio Code 支持擴展/插件(圖庫擴展,SDK 擴展,示例擴展)。

程式碼現已託管到GitHub:https://github.com/microsoft/vscode

Visual Studio Code 編輯器部分代碼來自GitHub Atom,但是有一些Atom 編輯器沒有的功能,比如智能感應。
Anders這位大神演示VS Code上開發AngularJS,他介紹了Google如何使用VS Code和TypeScript來開發AngularJS的下一版本

AngularJS團隊現場演示推薦AngularJS用戶使用VS Code。
三、微軟送大禮Visual Studio Dev Essentials
全新免費且已即時上線的Visual Studio Dev Essentials項目。通過這項技術,開發者們將能夠在其喜歡的任何設備和任意系統上打造應用,從而減少其額外的投資成本。


參與該項目的開發者們可訪問Visual Studio社群、程式碼和團隊服務、Parallells Desktop等工具和資源,以及在Pluralsight、Wintellect和Xamarin上培訓(明年年初上線,可選$25美元的Azure credit)。

微軟還介紹了按月或按年付費的Visual Studio專業版與企業版的雲訂閱服務。為了讓開發者的生活更加輕鬆,該公司還向所有人開放了其Microsoft Graph API(只需通過單一授權即可訪問)。

免費獲取成套的開發資源,包含下列內容:
開發工具
Visual Studio Community*
Visual Studio Code
Visual Studio Express
Team Foundation Server Express
學習資料
Pluralsight (為期 3 個月的訂閱)*
WintellectNOW (為期 3 個月的訂閱)*
Microsoft 虛擬學院、
HackHands Live Programming 幫助(25 美元信用)*
優先級論壇支持*
雲端資源
Azure 信用25 美元/月,提供12 個月)*
供五名用戶使用的Visual Studio Team Services 帳戶*
App Service 免費層
PowerBI 免費層
HockeyApp 免費層
Application Insights 免費層
跨平台開發資源
Parallels Desktop® for Mac Pro Edition (為期3 個月的訂閱)*
Parallels® Access (為期3 個月的訂閱)*
Windows 10 Enterprise VHD (為期 60 天)
Office Online 應用
獲取地址:https://www.visualstudio.com/free-developer-offers-vs
四、Visual Studio安卓模擬器可以運行在Mac上
Visual Studio 2015中提供了一個獨立的安卓模擬器,這個模擬器的運行速度是Google模擬器的3-5倍,佔用內存僅有不到1/3,對於移動應用開發者來說是非常好用的武器。現在這個模擬機也可以運行在Mac OSX上了。這個模擬器可以獨立安裝,獨立運行,即使你不使用Visual Studio進行開發,也可以使用這個模擬器作為你的安卓開發環境的一部分。
下載地址: https://www.visualstudio.com/zh-cn/features/msft-android-emulator-vs.aspx
昨晚的直播除了上面這些還有非常多的亮點,可以通過https://channel9.msdn.com/ 上觀看回顧。
內文來源為:tinyurl.com/pdpzvav

網智數位-軟體開發

2015年11月18日 星期三

WPF – VisualBrush 劃刷 功能介紹


      在開發公司套裝軟體產品時,在 Windows平台 下公司團隊幾乎都採用 Windows Form 或 WPF兩個技術,今年的專案因為某些原因幾乎全部開始全部採用 WPF技術,當然研發過程也面臨了不同的技術適應期,但隨著專案的開發過程,團隊漸漸越來越喜愛WPF技術,因為不論在繪圖界面呈現,開發速度的產能,效益比逐漸明顯出來,尤其是在 XAML 語法的特性,明顯界面與程式邏輯分離的架構,程式相對乾淨了許多,今年下半年公司也因為某些因素,投入繪圖技術的研究,在WPF的支援下,許多客戶的要求都可以快速的開發因應…
      而今天我也想要分享WPF一個繪圖呈現的一個利器- VisualBrush 畫刷 功能,VisualBrush主要特性是可以複製現有視窗特定的控制箱、元素、容器等區塊的外觀,也就是可以快取下來,好像一面鏡子,然後可以在其他地方顯示,實作方式事實上非常簡單,這邊我就帶大家來看一個範例…
   
  1: <Window x:Class="VisualBrush.MainWindow"
  2:         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3:         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4:         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  5:         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  6:         xmlns:local="clr-namespace:VisualBrush"
  7:         mc:Ignorable="d"
  8:         Title="MainWindow" Height="600" Width="800">
  9:     <Grid>
 10:         <Grid.ColumnDefinitions>
 11:             <ColumnDefinition>
 12:             </ColumnDefinition>
 13:             <ColumnDefinition >
 14:             </ColumnDefinition>
 15:         </Grid.ColumnDefinitions>
 16:         <Grid.RowDefinitions>
 17:             <RowDefinition></RowDefinition>
 18:             <RowDefinition></RowDefinition>
 19:         </Grid.RowDefinitions>
 20:         <Button x:Name="btn1" Grid.Column="0" >網智數位-軟體開發 , WPF - VisualBrush </Button>
 21:         <Rectangle  Grid.Column="1"  >
 22:             <Rectangle.Fill>
 23:                 <VisualBrush Visual="{Binding ElementName=btn1}"></VisualBrush>
 24:             </Rectangle.Fill>
 25:         </Rectangle>
 26: 
 27:         <!--<Button x:Name="btn2" Grid.Row="1" Grid.Column="0" Background="Red">網智數位-軟體開發 , WPF - VisualBrush</Button>-->
 28:         <Image Source="gril.png" x:Name="img1" Grid.Column="0" Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"  Stretch="Fill"></Image>
 29:         <Rectangle  Grid.Column="1" Grid.Row="1" >
 30:             <Rectangle.Fill>
 31:                 <VisualBrush Visual="{Binding ElementName=img1}"></VisualBrush>
 32:             </Rectangle.Fill>
 33:         </Rectangle>
 34:     </Grid>
 35: </Window>
 
重點在我用黃色標示起來的程式碼,很簡單透過 Binding 機制,我分別將2個矩形 Rectangle 的內容區域,放入 VisualBrush ,而各分別繫結至為 Button的外觀 和 Image 圖片的外觀,之後這2個 Rectangle矩形就好像2面鏡子分別對應Button跟Image… 
執行結果如下
image_thumb[11] 
 
網智數位-軟體開發 

2015年7月29日 星期三

軟體開發之專案管理﹣經驗亂談(一)

     最近因為承接了某大型軟體開發案,時程開發案停滯無法前進,幾乎承接軟體開發的程式設計師都無法繼續進行,開發團隊內部士氣低落、出現小爭執,每個人多少產生一些憂慮,還好這次組成的團隊都是真的經驗老道的,抗壓性極強大無比,隨時都可以因為專案的政治因素、技術因素,而內部激勵改變......,










        剛好最近也抽空看了前陣子買的一本極度暢銷書 「人月神話」﹣40週年紀念版,就開宗明義的說,專案管理最大問題之一就是所謂的 「專案時程安排的重要性 」,儘可能的初期規劃時程、所需人力都在合理範圍,不過當過專案經理的人都經歷過,合理時程範圍可以說是神話一般,客戶端的壓力、預算壓力,所以為了可以接到客戶的訂單,打死都要充胖子 ,即使明明開發時程明明需要 二 年也會變成縮短(甚至一半時間為 一 年),而這樣的死刑是每天都上演在軟體專案裡,很多專案主管都認為等到開發時程延遲,就快點花錢找新人、找武林高手,可是呢????結果呢???專案時程延遲的越來越嚴重,人力預算也投入了,怎麼效果沒預期那樣,第一,當多加一個人力,溝通的時間是相對增加的;第二即使再厲害的武林高手,也是需要一段時間去了解現行軟體的框架、領域知識(Domain-KnownHow),這前題下是之前SA分析的文件、SD開立的規格都是有高水準的,但通常都是...客官們你們知道的 ,有些專案更本因為時程的壓力,程式開發人員根本早就不遵守規則,UI界面層出現存取SQL語法、長長的if...else...程式碼,這種狀況下,資深高手也只能.....時間還是延遲,打掉重練,不然只能跟上帝禱告吧!

     [人月神話]很清楚的表達,無止境的加入人力已經延遲嚴重專案裡,不會比知道時間估算錯誤,坦然面對調整後續的專案時程規劃,來的有效率。
再來成功的軟體專案,都是需要成熟穩定極佳的框架,這可以達成開發一致性、有效率,專案管理溝通過程是需要透過文件來溝通,而不是省略該有的分析文件用口述的方式,這是莫大的災難啊!軟體專案你偷工減料少了那些該做的事前工作,相信我後面一定會加倍奉還 ,軟體專案真的就是類比開發建設案(蓋房子啦),你設想你少了好的建築圖、設計圖,然後口述跟A工人說你去怎麼做、B工人你怎麼做,大家各自做各自自己認為的樣子,結果.....失敗中的失敗.......


2015年7月8日 星期三

新合作、新契機、邁向新挑戰、尋找夥伴

          最近公司跟一個在行銷創新、創投人脈、在知名外商服務許久,非常有經驗的團隊合力共組一個比賽團隊,是要經營 Platform(平台),跟以往公司專注軟體專案、系統建置委外模式完全不同,但經營一家公司我思考了很久,才現在的穩定現金流模式下,我必須大膽嘗試不同合作模式,共同組成一個合作團隊,有時創業真的更多時間選擇什麼要先放棄,集中資源到一個機會發展性可能有更大突破的,所以在這樣的前題下,我馬上答應(事實上我心裡想,知道困難度很高,但心中有個力量就是要去跟各種不同的人一起合作,可以互相學習。








          在新團隊各自分工情況下,我當然負責投入公司最擅長的軟體資訊技術,規劃系統架構,前端的網頁程式、Android  APP、iPhone APP、RWD,以及後端採取的技術 SQL Server、WebAPI、爬蟲程式撰寫,不過接下了任務才發覺因為這個合作過程,竟然幾乎每個星期陌生客戶尋求軟體開發承包,竟然詢問度忽然比以往多了2~3成要求報價,有時真的要嘛客戶都沒上門,要嘛都忽然同時出現,但也因為新團隊合作,我答應在先所以我必須負責的態度,所以很多新開發的合作案,都必須延後甚至捨棄(我很心疼,公司想多賺點錢,有公司開銷啊),希望新客戶能夠體會,如果有機會,「網智數位﹣軟體開發」非常願意承包各種開發案,也更期待可以用心服務每個客戶。

          不過,最近除了開發各種 WPF User Control給舊客戶的軟體開發人員使用外,挪出了好多時間研究 Amazon Product Advertising API 、eBay API、Walmart Open API 、FB API、Llinkedin API, 真的發覺每個大型電子商務平台、社群平台的API複雜度,以及提供的白皮書技術文件每個幾乎都超過700頁,真的是一個不知道哪來的勇氣....後續還要培養 Android 、RWD的人投入開發,真的是機會也是累死人的挑戰,如果有軟體開發人員有興趣,對整合這些大型官網的API有興趣研究,想要參與一個未來有可能性被創投投入一定金額的團隊,那你可以寫信給我 ( allen@netqna.com ) , 加入這個團隊,你會發覺學到東西不一樣哦,而且真的是經營網路產業(互聯網),不是專案型公司哦,普遍來說專案公司這幾乎都是幸苦爆肝(當然也不是絕對啦)。

          另外網智數位資訊公司,也特別徵求有 Java 開發經驗、.Net 開發經驗的人,目前非常缺人,待遇基本上都是超過5萬以上,如果有意願可以一樣寫信給  Allen (allen@netqna.com) 。



2015年5月9日 星期六

創業任何事堅持也可以「海闊天空」


創業任何事堅持也可以「海闊天空」

          這星期,Allen 我認真的跑客戶、等待時間我會拿出筆電研究接下來要談合作的事情,我不是專門是個業務出身的,但創業就必須面對這個議題,這也是IT技術底子創業家必須心裡調整與釋懷的過程,因為沒有業績,就等於沒有了「現金流」,也因為我超過10年的工作生涯,我一直專注IT專業、企業流程領域知識,但我實實在在更渴望真的可以利用IT資訊科技,真正幫到我的客戶,畢竟我知道如果對方沒有真正的效益,可能是第一次合作,也是最後一次合作,所以我真的一直提醒自己不能只為了賺錢而忽略了「雙方的互利」,但記得不要砍我的價太離譜,因為我公司要生存啊!!









          但我要說的客戶有些真的是可以是朋友也可以是好搭檔,這星期因為團隊成員真的一直忙著一個大型物流業的系統開發委外案(因為合約保密條款所以不能公開),但有個客戶因為網路環境的問題,導致內部一些運作停擺,打電話給我,衡量權重我有必要自己先暫停跑去親自了解與處理,發覺真的網路儲存設備出問題,這樣也花了我超過半天的時間,但這樣工作過程也聊起互相創業的想法與壓力,同樣是創業者的辛苦酸甜苦辣,對方客戶因為辦公司夠大,竟然要免費的提供辦公室空間給我團隊成員利用,所以有時候我覺得創業是可以認識更多奮鬥的朋友,也更可以創造雙贏。

          而從工作室正式成為公司後,一堆朋友介紹案子打電話給我,真的創業來說,人脈是無形的最重要的價值,更有桃園的軟體公司老闆(前輩),打電話一起合作,還提醒我收款注意事項,但創業後,我知道我只有更認真把公司、以及好的團隊成員一起共同奮鬥一起分享成果,今天我想說的是任何事一定都是起頭難,但一定要把壓力轉變成樂觀的態度,因為最好的果實都在努力堅持後才會出現,建立自己與公司的目標與價值觀。

          網智數位﹣會堅持品質、專業技術、服務態度,目標成為一個資訊科技、軟體開發的「隱形冠軍」。也更希案子如果你有軟體開發(.Net 、Java、iPhone & Android Platform)、網頁設計、業務合作經驗,寫信或電洽我,但合作夥伴一定要堅持品質、服務態度,「網智數位」案子會越來越多哦,真的歡迎您的加入,我們團隊目前也正在跟產業談雲端軟體服務的合作雛形計劃。

         也歡迎有客戶想要我們提案,針對您的產業領域知識,讓我們團隊進行最專業、最仔細的系統分析,設計與開發屬於您需要的軟體需求。


合作機會 allen@netqna.com ,0920﹣883﹣870 黃先生(Allen)
提案報價 service@netqna.com  or  allen@netqna.com , 0920﹣883﹣870 黃先生(Allen)



2015年5月5日 星期二

網智數位正式轉型為數位資訊公司

很開心,最近經過幾年的努力,網智數位擁有越來越多的客戶合作機會,也因此為了更認真、更專業的態度服務客戶,我們正式成立網智數位有限公司,也會繼續堅持專業技術與企業的領域知識不斷的深入了解客戶的實際需求,量身定做符合客戶的IT整體規劃,不論你有軟體客製化、APP開發、網路行銷、美工設計,我們團隊皆有服務,也感謝舊客戶以及新客戶給我們網智數位每個服務機會。





網智數位 團隊 感謝您....

洽談合作方式
黃先生 Allen
allen@netqna.com
0920-883-870



2015年1月15日 星期四

管理軟體商機

     昨晚參加一個各產業領域交流的聚會,認識許多新朋友,也激發我不一樣的思維,有人知道我從事資訊業,大致也會問我 APP 委外開發、Web網頁開發雲端導入等相關問題,事實上我一直思考的是,事實上資訊管理軟體長期是屬於被動需求 ,也就是通常不是一家企業會很主動的導入軟體,除非當企業遇到管理問題(例如庫存混亂、成本無法估算、人力成本等),才開始被動的想要藉由管理軟體的幫助下,來提升企業的管理便利性。











     例如我昨晚認識一個作硬碟損壞救援的公司,還是透過內部自行做的表單,來記錄客戶的報修、保固、會員資料,但因為實在太多表單,根本資料無法一致化,客戶多以後,真的才開始發現內勤服務人員,光是維護輸入這些資料就要重覆輸入,我也很誠心的建議可以根據內部真正的營運流程建置一個符合自己的管理系統,這樣企業的管理自然而然就會提高,事實上所需預算不如他們想象的高。


   
     雖然最近一直忙於客戶的專案,比較沒空寫文章,但我盡可能抽出時間的學習各種知識,不論是IT技術還是管理知識、企業流程,也思考個人與團隊的下一個發展契機,身處於快速變化的資訊產業,技術的革新以及衝擊,我要求自己與團隊在現有的技能上面,也要突破再進步,但時間的有限的狀況下,也開始思考合作聯盟,利益共享的機會,與人競爭不如一起合作,這也是我近些日子最大的改變,因為我目前無法要求自己各種專業技術、知識都可以精通,我多年來認真專研企業資訊系統與微軟.NET & SQL Server 解決方案(當然也有其他平台),因為自己深深認為選擇一個平台去專研,變成自己的工具,在透過觀察與經驗去了解各產業客戶對資訊系統的需求,真正要求團隊開發出客戶需要的功能,而不是爭論平台的優劣勢。





 

     而隨著雲端化的浪潮下以及智慧手機、平板APP的普及,開始許多朋友(客戶)會問我是否可以利用 APP協助他們,達到某些用途,例如 業務在外面可以下訂單、主管可以隨時看任何報表、網頁的購物車是否也可以開發手機版,這些都是商機,也需要各種不同專業技術的IT人共同合作,如果你有相關技能,也真的歡迎寫mail 給我 (allen@netqna.com),大家一起合作發展,合作模式都可以討論。


2014年11月12日 星期三

[Entity Framework] 效能深入探討(二)

     在上一篇我花了一些時間談到,當我們載入資料庫模型是屬於 1 對多 (One-To-Many)時,預設值 Entity Framework 6 是利用一個稱為 Lazy Loading 機制,也就是當需要一個資料的其他相關(關聯)資料時,EF 才會產生SQL語法去跟後端資料庫要求相關資料,而資料應用程式效能的殺手之一,就是太繁複去跟後端資料庫來回存取,為了克服 EF 預設行為的效能問題,我想來介紹一個 EF 另外一個機制術語,稱為 Eager Loading ....


 

     使用 Eager Loading 機制,主要可以在一開始讀取資料時,例如讀取 Customer Table 時,如果我們知道後續一定會讀取相關聯的資料表(類別),如案例的 CustomerCate Table、CustomerEvent Table,那麼我們就可以在第一次讀取 Customer Table 時就一次讀取所有相關的資料表,這樣後續應用程式需要相關資料時,只要在記憶體立即讀取,而不是需要用到時,才延遲跟資料庫索取相關資料,解釋那麼多,到底程式語法該如何實作呢?我們會用到一個方法(Method)為 Include ....

    PS.這次實作我完全根據 上一篇[Entity Framework] 效能深入探討(一) 繼續介紹,前端我暫時利用 Windows Form 來簡單的 Demo
,然後我會把焦點放在 Include Loading(1) 與  Include Loading(2) 的 程式語法
 

在  Include Loading(1) Button Click事件,我撰寫了一些程式碼:

  1. this.richTextBox1.Clear();
  2. this.richTextBox1.AppendText("使用 Eager Loading 機制 Include Method ! \r\n");
  3. this.richTextBox1.AppendText("------------------------------------------------------------------------- \r\n");

  4. using (CRMEF ef = new CRMEF())
  5. {
  6.      var customers = ef.Customer.Include("CustomerCate").Include("CustomerEvent");

  7.      foreach (var cust in customers)
  8.      {
  9.           this.richTextBox1.AppendText("客戶編號 : " + cust.No + " 客戶姓名 :" + cust.ENmae + "\t  類型 :" + cust.CustomerCate.Name + "\r\n");
  10.           this.richTextBox1.AppendText("--------------------------------事件記錄------------------------------------ \r\n");

  11.           foreach (var evt in cust.CustomerEvent)
  12.           {
  13.                this.richTextBox1.AppendText(evt.Desc + "\r\n");
  14.           }

  15.           this.richTextBox1.AppendText("\r\r\n");
  16.      }
  17. }

     注意上述程式碼的第 7 行我使用了2次 Include 方法,並在該方法傳遞是關聯類型的字串,透過這樣的方式,但程式第一次需要讀取 Customer 資料表時,
Entity Framewok(EF)就會自動產生的 SQL語法是把 Customer、CustomerCate、CustomerEvent 3個 Table,一次完全跟後端資料庫的索取,並記錄到記憶體(DataContext Cache),所以整個 SQL 傳輸只有 1 次,而不是上一篇介紹的 7 次哦(效能差很大,這也是一般書上很少寫的)。

底下我列出我追蹤的 SQL 語法如下
  1. SELECT
  2.     [Project1] .[C1] AS [C1],
  3.     [Project1] .[No] AS [No],
  4.     [Project1] .[CName] AS [CName],
  5.     [Project1] .[ENmae] AS [ENmae],
  6.     [Project1] .[CateCode] AS [CateCode],
  7.     [Project1] .[Code] AS [Code],
  8.     [Project1] .[Name] AS [Name],
  9.     [Project1] .[C2] AS [C2],
  10.     [Project1] .[EventID] AS [EventID],
  11.     [Project1] .[CustNo] AS [CustNo],
  12.     [Project1] .[Desc] AS [Desc],
  13.     [Project1] .[CreateDate] AS [CreateDate]
  14.      FROM ( SELECT
  15.         [Extent1] .[No] AS [No],
  16.         [Extent1] .[CName] AS [CName],
  17.         [Extent1] .[ENmae] AS [ENmae],
  18.         [Extent1] .[CateCode] AS [CateCode],
  19.         [Extent2] .[Code] AS [Code],
  20.         [Extent2] .[Name] AS [Name],
  21.         1 AS [C1],
  22.         [Extent3] .[EventID] AS [EventID],
  23.         [Extent3] .[CustNo] AS [CustNo],
  24.         [Extent3] .[Desc] AS [Desc],
  25.         [Extent3] .[CreateDate] AS [CreateDate],
  26.          CASE WHEN ([Extent3]. [EventID] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C2]
  27.          FROM   [dbo]. [Customer] AS [Extent1]
  28.          LEFT OUTER JOIN [dbo] .[CustomerCate] AS [Extent2] ON [Extent1] .[CateCode] = [Extent2].[Code]
  29.          LEFT OUTER JOIN [dbo] .[CustomerEvent] AS [Extent3] ON [Extent1] .[No] = [Extent3].[CustNo]
  30.      )  AS [Project1]
  31.      ORDER BY [Project1].[No] ASC, [Project1] .[Code] ASC , [Project1]. [C2] ASC


看吧看吧,是不是 EF很聰明的產生一個完全都包含的表格(Table)。


接下來,我們來看第二種 Include 語法的寫法,2種執行結果都相同。

  1. this.richTextBox1.Clear();
  2. this.richTextBox1.AppendText("使用 Eager Loading 機制 Include Method 2 ! \r\n");
  3. this.richTextBox1.AppendText("------------------------------------------------------------------------- \r\n");

  4. using (CRMEF ef = new CRMEF())
  5. {
  6.      var customers = ef.Customer.Include(t => t.CustomerCate).Include(t => t.CustomerEvent);

  7.      foreach (var cust in customers)
  8.      {
  9.           this.richTextBox1.AppendText("客戶編號 : " + cust.No + " 客戶姓名 :" + cust.ENmae + "\t  類型 :" + cust.CustomerCate.Name + "\r\n");
  10.           this.richTextBox1.AppendText("--------------------------------事件記錄------------------------------------ \r\n");

  11.           foreach (var evt in cust.CustomerEvent)
  12.           {
  13.                this.richTextBox1.AppendText(evt.Desc + "\r\n");
  14.           }

  15.           this.richTextBox1.AppendText("\r\r\n");
  16.      }
  17. }

以上介紹完 Eager Loading Inclue 的技巧,希望各位操控 EntityFramework 6 可以更加熟析在最適當的狀況下,來調整預設存取行為機制。



2014年11月9日 星期日

[Entity Framework] 效能深入探討(一)

      作者我在使用Entity Framewok開發時,最常聽到的一句話就是,Entity Framework 是否"好像"效能很慢喔,在微軟剛推出Entity Framewok前(事實上微軟真的這方面算是進展很慢,其他程式陣營早就有相關的Framework,例如 Java 的 Hibernate,不過後來真的速度改版的很迅速,微軟都這樣玩法),我會很肯定的回答"是",如果當時要採用 Entity Framewok時,我想可能最大的益處就是可以在程式開發過程時,比較可以使用"概念模型"(Conceptual Model)以及 OOP(物件導向)的思維導向,也可以避免程式開發人員在寫程式盡可能避免了 SQL Script,當然也避免了一些開發人員真的不太會寫 SQL,相信我真的還遇到過,不過隨著Entity Framewok 發展到 Version 6 UP.., 我相信大多數是可以依靠 EF(Entity Framewok),而且開發速度的優勢已經是大多數優先考慮採用的原因,尤其現在到處都是 WEB API、MVC架構(EF歸於 Model  Layer),我們更需要好好學習一下,所以我打算寫幾篇關於 EF效能的底層技術與原理,畢竟 Entity Framewok 雖然把底層 SQL的工作,都幫你處理好,但你知道為何有時似乎效能真的好像還是很慢,所以我想直接跟讀者說一些原理,這也是市面上書籍似乎都沒在探討的.....

     我先在此介紹一個Entity Framework 的術語 Lazy Load , 它代表 延遲載入 預設值是成立(true)  。為了解釋何謂Lazy Load,我自己帶入一個案例來進行解釋
例如在我們 CRM系統裏有 [客戶類型]類別 (CustCate Class) , 而每個[客戶類型]可以有多個興趣的[客戶]類別 (Customer Class),此時很典型存在所謂的一對多 One-To-Many 的模型 ;而每個[客戶]類別也可以記錄此客戶相關的[客戶事件]類別(CustomerEvent Class)
,下面我列出了案例模型圖


根據上述模型我們來實作一個 Code First EF Model 
實作 Customer 、CustCate、CustomerEvent Class Code ....

    [Table("Customer")]
    public partial class Customer
    {
        public Customer()
        {
            CustomerEvent = new HashSet<CustomerEvent>();
        }

        [Key]
        [StringLength(15)]
        public string No { get; set; }

        [StringLength(10)]
        public string CName { get; set; }

        [StringLength(10)]
        public string ENmae { get; set; }

        [StringLength(10)]
        public string CateCode { get; set; }

        public virtual CustomerCate CustomerCate { get; set; }

        public virtual ICollection<CustomerEvent> CustomerEvent { get; set; }
    }

    
    [Table("CustomerCate")]
    public partial class CustomerCate
    {
        public CustomerCate()
        {
            Customer = new HashSet<Customer>();
        }

        [Key]
        [StringLength(10)]
        public string Code { get; set; }

        [Required]
        [StringLength(15)]
        public string Name { get; set; }

        public virtual ICollection<Customer> Customer { get; set; }
    }

    [Table("CustomerEvent")]
    public partial class CustomerEvent
    {
        [Key]
        [StringLength(36)]
        public string EventID { get; set; }

        [StringLength(15)]
        public string CustNo { get; set; }

        [Required]
        [StringLength(300)]
        public string Desc { get; set; }

        public DateTime CreateDate { get; set; }

        public virtual Customer Customer { get; set; }
    }

     
實作一個繼承 DbContext 的 EF 存取容器

    public class CRMEF : DbContext
    {
        public CRMEF()
            : base("name=EF")
        {
        }

        public virtual DbSet<Customer> Customer { get; set; }
        public virtual DbSet<CustomerCate> CustomerCate { get; set; }
        public virtual DbSet<CustomerEvent> CustomerEvent { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Customer>().ToTable("Customer");
            modelBuilder.Entity<CustomerCate>().ToTable("CustomerCate");
            modelBuilder.Entity<CustomerEvent>().ToTable("CustomerEvent");

            modelBuilder.Entity<Customer>().HasMany(e => e.CustomerEvent)
                                           .WithOptional(e => e.Customer)
                                           .HasForeignKey(e => e.CustNo);

            modelBuilder.Entity<CustomerCate>().HasMany(e => e.Customer)
                                               .WithOptional(e => e.CustomerCate)
                                               .HasForeignKey(e => e.CateCode);

            base.OnModelCreating(modelBuilder);
        }
    }


我也設計一個前端界面

在寫入測試資料 Button,先寫入基本資料以利後面的解說
private void btnTestData_Click(object sender, EventArgs e)
{
  try
   {
       using (CRMEF ef = new CRMEF())
        {
             CustomerCate cate1 = new CustomerCate() { Code = "Retail", Name = "零售商" };
             CustomerCate cate2 = new CustomerCate() { Code = "Direct", Name = "直客" };
             CustomerCate cate3 = new CustomerCate() { Code = "EC", Name = "網路消費者" };

             Customer cust1 = new Customer() { CustomerCate = cate1, No = "001", CName = "智慧零售商", ENmae = "Smart" };
             CustomerEvent custEvent1 = new CustomerEvent() { Customer = cust1, EventID = Guid.NewGuid().ToString(), Desc = "詢問新產品目錄", CreateDate = DateTime.Now };
             ef.CustomerEvent.Add(custEvent1);
             CustomerEvent custEvent2 = new CustomerEvent() { Customer = cust1, EventID = Guid.NewGuid().ToString(), Desc = "購買10套 網智數位 CRM 套裝軟體", CreateDate = DateTime.Now };
             ef.CustomerEvent.Add(custEvent2);
             Customer cust2 = new Customer() { CustomerCate = cate2, No = "002", CName = "柯P", ENmae = "柯P" };
             CustomerEvent custEvent3 = new CustomerEvent() { Customer = cust2, EventID = Guid.NewGuid().ToString(), Desc = "尋找物聯網的合作廠商", CreateDate = DateTime.Now };
             ef.CustomerEvent.Add(custEvent3);
             Customer cust3 = new Customer() { CustomerCate = cate3, No = "003", CName = "連勝吻", ENmae = "連勝吻" };
             CustomerEvent custEvent4 = new CustomerEvent() { Customer = cust3, EventID = Guid.NewGuid().ToString(), Desc = "網路行銷推廣", CreateDate = DateTime.Now };
             ef.CustomerEvent.Add(custEvent4);

             ef.SaveChanges();
             MessageBox.Show("Test Insert OK");
         }
    }
    catch { }
 }

執行後,我們可以看到後端資料庫就存在一下資料


現在有了案例的資料後,我就可以開始解釋何謂 Lazy Loading,在上述案例我們如果需要列出所有客戶以及他相關的活動事件,以及此客戶歸屬的類別,我把它寫在 "Lazy Loading" Button Click:

  1. private void btnLazyLoading_Click(object sender, EventArgs e)
  2. {
  3. this.richTextBox1.Clear();
  4. this.richTextBox1.AppendText("使用 Lazy Loading 讀取,系統預設行為! \r\n");
  5. this.richTextBox1.AppendText("------------------------------------------------------------------------- \r\n");

  6. using (CRMEF ef = new CRMEF())
  7. {
  8. var customers = ef.Customer;

  9. foreach (var cust in customers)
  10. {
  11. this.richTextBox1.AppendText("客戶編號 : " + cust.No + " 客戶姓名 :" + cust.ENmae + "\t  類型 :" + cust.CustomerCate.Name + "\r\n");
  12. this.richTextBox1.AppendText("--------------------------------事件記錄------------------------------------ \r\n");

  13. foreach (var evt in cust.CustomerEvent)
  14. {
  15. this.richTextBox1.AppendText(evt.Desc + "\r\n");
  16. }

  17. this.richTextBox1.AppendText("\r\r\n");
  18. }
  19. }
  20. }
執行後結果如下

看樣子結果都是沒錯的,但各位我要告訴你們,你知道 上述結果 Entity Framewok 是幫我們產生多少次 SQL語法嗎? , 以及來回跟後端資料庫查詢幾次嗎?
答案是 7 次 ,也就是說白話一點,就是 EF要來回跟後端資料庫溝通要得資料7次,才可以把我們要呈現的資料,完全取回來,各位如果客戶資料不是現在案例的3筆,而100筆...1000筆....甚至 10000筆以上呢?

我分別把我追蹤後的SQL 語法寫下:
第 1 次 SQL :
SELECT
    [Extent1].[No] AS [No],
    [Extent1].[CName] AS [CName],
    [Extent1].[ENmae] AS [ENmae],
    [Extent1].[CateCode] AS [CateCode]
    FROM [dbo].[Customer] AS [Extent1]

第 2 次 SQL :
exec sp_executesql N'SELECT
    [Extent1].[Code] AS [Code],
    [Extent1].[Name] AS [Name]
    FROM [dbo].[CustomerCate] AS [Extent1]
    WHERE [Extent1].[Code] = @EntityKeyValue1',N'@EntityKeyValue1 nvarchar(10)',@EntityKeyValue1=N'Retail'

第 3 次 SQL :
exec sp_executesql N'SELECT
    [Extent1].[EventID] AS [EventID],
    [Extent1].[CustNo] AS [CustNo],
    [Extent1].[Desc] AS [Desc],
    [Extent1].[CreateDate] AS [CreateDate]
    FROM [dbo].[CustomerEvent] AS [Extent1]
    WHERE [Extent1].[CustNo] = @EntityKeyValue1',N'@EntityKeyValue1 nvarchar(15)',@EntityKeyValue1=N'001'

第 4 次 SQL :
exec sp_executesql N'SELECT
    [Extent1].[Code] AS [Code],
    [Extent1].[Name] AS [Name]
    FROM [dbo].[CustomerCate] AS [Extent1]
    WHERE [Extent1].[Code] = @EntityKeyValue1',N'@EntityKeyValue1 nvarchar(10)',@EntityKeyValue1=N'Direct'

第 5 次 SQL :
exec sp_executesql N'SELECT
    [Extent1].[EventID] AS [EventID],
    [Extent1].[CustNo] AS [CustNo],
    [Extent1].[Desc] AS [Desc],
    [Extent1].[CreateDate] AS [CreateDate]
    FROM [dbo].[CustomerEvent] AS [Extent1]
    WHERE [Extent1].[CustNo] = @EntityKeyValue1',N'@EntityKeyValue1 nvarchar(15)',@EntityKeyValue1=N'002'

第 6 次 SQL :
exec sp_executesql N'SELECT
    [Extent1].[Code] AS [Code],
    [Extent1].[Name] AS [Name]
    FROM [dbo].[CustomerCate] AS [Extent1]
    WHERE [Extent1].[Code] = @EntityKeyValue1',N'@EntityKeyValue1 nvarchar(10)',@EntityKeyValue1=N'EC'

第 7 次 SQL :
exec sp_executesql N'SELECT
    [Extent1].[EventID] AS [EventID],
    [Extent1].[CustNo] AS [CustNo],
    [Extent1].[Desc] AS [Desc],
    [Extent1].[CreateDate] AS [CreateDate]
    FROM [dbo].[CustomerEvent] AS [Extent1]
    WHERE [Extent1].[CustNo] = @EntityKeyValue1',N'@EntityKeyValue1 nvarchar(15)',@EntityKeyValue1=N'003'


這就是 Entitfy Framework 的預設行為 Lazy Loading , 上述 C# 語法我們先列舉了所有客戶的清單,此時 EF 就會產生 第一個 SQL 語法 是讀取後端 [dbo].[Customer] Table 的 SQL ,
而我們再依序根據每筆客戶分別讀取了客戶類型,此時 EF 又會去跟後端資料庫要求讀取 [dbo].[CustomerCate] Table ,所以有幾筆客戶資料,他就會來回跟資料庫讀取 [dbo].[CustomerCate] Table,各位這就是效能瓶頸所在
接下來我們繼續讀取每筆客戶的系統事件,此時 EF 又要懶惰 (Lazy Loading)的再去跟後端資料庫取得  [dbo].[CustomerEvent] 資料表,看吧!,系統如果資料量大一點,這樣大部分人使用 EF (Entitfy Framework) ,一定死了,被客戶抱怨死了,
此時通常工程師或開發人員就會抱怨 Entity Framewok好爛,效能好差,還是用ADO.Net好....這也是我公司工程師常跟我說類似的話,但如果你知道底層的原理,這都是可以操控自如的,完全可以任意操控EF,使它可以不用笨到來來回回奔走,
至於如何做呢? 就讓我留著下一回好好地告訴大家。。。。