軟體開發(軟件開發)

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

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

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

商用軟體-客製化設計

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

IOT 物聯網-系統開發

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

雲端VPS虛擬主機租用

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

ERP軟體客製化導入

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

搜尋引擎最佳化SEO

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

服務宗旨

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

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

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

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

顯示具有 c# 標籤的文章。 顯示所有文章
顯示具有 c# 標籤的文章。 顯示所有文章

2016年10月24日 星期一

Windows 10 的 UDP 與 TCP 網路通訊實作案例一(軟體開發、軟件開發、程式設計、程式開發)

        今年公司承包了許多大型專案,都是必須用到網路存取技術,例如 圖控軟體我們就必須透過 TCP 協定跟硬體設備溝通,來讀取上萬台工業風扇裝置的轉速、溫度等訊息;再來還有影像監控軟體也是大量用到TCP/UDP、Web API網路協定存取,因此在開發各種軟體時,很多機會勢必需要用到網路通訊的技術。

        而這篇教學技術文章,我特別是針對微軟的 Windows 10 平台上,也就是所謂的 Windows 10 通用應用開發(Universal APP,UAP),示範關鍵的程式技術,我想分為 2 篇文章分別介紹 UDP 與 TCP 存取技巧,而這篇文章就先針對 UDP協定來介紹,UDP協定是個無連接(不可靠)的協議,它只提供資料的不可靠傳遞,它一旦把應用程式發給網路層的資料傳送出去,就不保留資料備份(所以UDP有時候也被認為是不可靠的資料報協定),UDP在IP資料報的頭部僅僅加入了復用和資料校驗(欄位),但它相對于TCP 協定來說,資源耗用少、而且處理速度夠快,所以常被用在傳輸要求沒有那麼嚴格的條件下,例如:聊天訊息、網路視訊、語音傳遞。

在 WIndows 10 的 UAP/UWP 平台上,微軟透過一個 DatagramSocket 類別來封裝了所有有關 UDP 網路存取的相關功能。

我將示範 伺服器端(Server) 與 用戶端(Client) 的程式技巧

在 Server 端,主要步驟有

1.建立一個 DatagramSocket 實體物件。

2.建立一個對應的 MessageReceived 事件,它將用來接收 Client 發送的訊息。

3.使用 BindEndPointAsync 方法來綁定本機的位址(IP)、端口(Port),如果是需要本機的所有網路位址(有多張網卡、無線網路等)都可以監聽訊息,我們就改用 BindServiceNameAsync 方法,然後只要指定要擊結對應的Port即可。

而在 Client 端,主要是一樣建立一個 DatagramSocket 實體物件,在透過該 DatagramSocket 提供的 GetOutputSteamAsync() 方法,並在該方法傳入 Server端IP位址、Port即可。

在 XAML 界面我為了好示範,我將 Server 界面跟 Client 界面 放在一起,分別為2個頁籖,這是使用 <Pivot> 元素 (我在這邊不花時間解釋 XAML Code 知識,但開發 Windows 10 XAML 是必備的基本語法,一定要會而且很熟,我就特別喜歡 XAML Code)。

XAML 畫面如下圖

<Pivot>
           <PivotItem Header="Server 伺服器端">
               <Grid>
                   <Grid.RowDefinitions>
                       <RowDefinition Height="Auto"/>
                       <RowDefinition />
                   </Grid.RowDefinitions>
                   <StackPanel>
                       <TextBlock Text="Server IP地址:" FontSize="20"/>
                       <TextBlock Name="tbIp" FontSize="36" IsTextSelectionEnabled="True"/>
                   </StackPanel>
                   <ListView Grid.Row="1" Margin="0,15,0,3" Name="lvMsg">
                       <ListView.Header>
                           <TextBlock Foreground="LightGreen" Text="已截取的Client端請求" FontSize="20"/>
                       </ListView.Header>
                       <ListView.ItemTemplate>
                           <DataTemplate>
                               <StackPanel Margin="6,20">
                                   <TextBlock FontSize="20" Foreground="Yellow">
                                       来自
                                       <Run Text="{Binding Path=FromIP}"/>
                                       的消息:
                                   </TextBlock>
                                   <TextBlock TextWrapping="Wrap" FontSize="24" Text="{Binding Path=Message}"/>
                               </StackPanel>
                           </DataTemplate>
                       </ListView.ItemTemplate>
                   </ListView>
               </Grid>
           </PivotItem>
           <PivotItem Header="Client 端">
               <StackPanel>
                   <TextBox Name="txtServer" Header="Server IP:"/>
                   <TextBox Name="txtMessage" Header="發送訊息內容:" TextWrapping="Wrap" Height="200"/>
                   <Button HorizontalAlignment="Center" Content="送出" Padding="20,0" Click="OnSend"/>
               </StackPanel>
           </PivotItem>
       </Pivot>

程式運行畫面如下圖

(Server 頁籖)

2016-10-23_23-25-03

(Cilent 頁籖)

2016-10-23_23-25-39

 

看完主要的界面宣告與結果,就開始來講解幾個主要核心程式碼

步驟 1.首先我宣告了 1 個常數 servicePort ,用於指定伺服器服務的端口Port.
    再宣告 2 個欄位(Fields), 作用於 Server UDP 與 Client UDP。

image

步驟 2.在 MainPage 建構子,宣告了載入實際時 綁定 Server 與 Client 端的 UDP Socket 。
   以及 Unload 時,釋放資源。

還有 我還綁定一個 Server 端要監聽 Client 端發送的訊息請求事件

image

步驟 3. Server 監聽事件 ,核心程式碼邏輯

相關程式碼,都附上註解

image

在上述 步驟 1 ~ 步驟 3 ,就完成 Server 端的主要監聽任務。

而 Client 端接下來的邏輯,就是在 Client 頁籖界面,輸入 Server 的 IP 位址、端口,以及要發送的內容,相關程式碼邏輯如下

OnSend() 是在 Client 頁籖界面,執行【送出】按鈕對應的動作方法

image

以上完成後,讓我們就可以來執行看看

在 Client 端頁籖 輸入訊息內容

image

在 Server 端監聽到的訊息如下

image

 

 

網智數位-軟體開發(軟件開發)
針對各特殊產業都可以量身定做符合貴公司的需求,別人無法克服的就是我們的挑戰
業務合作、軟體委外開發
業務窗口:allen@netqna.com
聯繫電話:0920-883-870
skype: netqna
line:netqna
微信:netqna
黃先生 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月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] 
 
網智數位-軟體開發 

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 可以更加熟析在最適當的狀況下,來調整預設存取行為機制。