Entity Framework 6 Recipes 2nd Edition(11-1)譯 -> 從“模型定義”函數返回一個標量值

来源:http://www.cnblogs.com/kid1412/archive/2016/01/24/5154487.html
-Advertisement-
Play Games

第11章函數函數提供了一個有力代碼復用機制, 並且讓你的代碼保持簡潔和易懂。它們同樣也是EF運行時能利用的資料庫層代碼.函數有幾類: Rowset Functions, 聚合函數, Ranking Functions, 和標量值函數.函數要麼確定,要麼不確定。當用一些指定的值調用函數,而函數返回的結...


11函數

函數提供了一個有力代碼復用機制, 並且讓你的代碼保持簡潔和易懂。

它們同樣也是EF運行時能利用的資料庫層代碼.函數有幾類: Rowset Functions, 聚合函數, Ranking Functions, 和標量值函數.

函數要麼確定,要麼不確定。當用一些指定的值調用函數,而函數返回的結果總是一樣時,它就是確定的函數。當甚至用同樣的一些值調用時,而函數每次返回的結果也可能不一樣,它就是不確定的函數。

在前七小節,我們探討“模型定義”的函數,這些函數允許我們在概念層上創建。這些函數依照EF類型和你的模型實體來定義。這樣使得它們能便捷地通過數據存儲執行。

在剩下的小節,我們就展示如何使用被EF定義的函數和資料庫層的函數.

這些函數允許你影響已有的代碼,在EF運行時或更接近於你數據的資料庫層.

11-1. 從“模型定義”函數返回一個標量值

問題

想在概念模型定義一個函數,接受一個實體的實例,並且返回一個標量值.

解決方案

假設已有一個如Figure 11-1.所示模型

 

Figure 11-1. 一個產品和分類的模型

接下來創建一個接受一個Category 實體實例並返回給定Category 里所有product的平均單價:

1. 在解決方案資源管理器中,右擊 .edmx 文件,選擇“打開方式” ➤ XML 編輯器.

2.在.edmx文件的概念模型(conceptual models)節點<Schema>標簽里,插入Listing 11-1里的代碼,這樣就在模型里定義了函數。

Listing 11-1. Definition of the AverageUnitPrice() Function in the Model

        <Function Name="AverageUnitPrice" ReturnType="Edm.Decimal">

          <Parameter Name="category" Type="EFRecipesModel1101.Category" />

          <DefiningExpression>

            ANYELEMENT(Select VALUE Avg(p.UnitPrice) from EFRecipesEntities1101.Products as p where p.Category == category)

          </DefiningExpression>

        </Function>

3. 插入和查詢這個模型的代碼,如Listing 11-2所示.

    class Program

    {

        static void Main(string[] args)

        {

            RunExample();

 

            Console.WriteLine("\nPress any key to exit...");

            Console.ReadKey();

        }

        static void RunExample()

        {

            using (var context = new EFRecipesEntities1101())

            {

                context.Database.ExecuteSqlCommand("delete from chapter11.product;delete from chapter11.category");

                var c1 = new Category { CategoryName = "Backpacking Tents" };

                var p1 = new Product

                {

                    ProductName = "Hooligan",

                    UnitPrice = 89.99M,

                    Category = c1

                };

                var p2 = new Product

                {

                    ProductName = "Kraz",

                    UnitPrice = 99.99M,

                    Category = c1

                };

                var p3 = new Product

                {

                    ProductName = "Sundome",

                    UnitPrice = 49.99M,

                    Category = c1

                };

                context.Categories.Add(c1);

                context.Products.Add(p1);

                context.Products.Add(p2);

                context.Products.Add(p3);

                var c2 = new Category { CategoryName = "Family Tents" };

                var p4 = new Product

                {

                    ProductName = "Evanston",

                    UnitPrice = 169.99M,

                    Category = c2

                };

                var p5 = new Product

                {

                    ProductName = "Montana",

                    UnitPrice = 149.99M,

                    Category = c2

                };

                context.Categories.Add(c2);

                context.Products.Add(p4);

                context.Products.Add(p5);

                context.SaveChanges();

            }

            // with eSQL

            using (var context = new EFRecipesEntities1101())

            {

                Console.WriteLine("Using eSQL for the query...");

                Console.WriteLine();

                string sql = @"Select c.CategoryName, EFRecipesModel1101

                                .AverageUnitPrice(c) as AveragePrice from

                                                    EFRecipesEntities1101.Categories as c";

                var objectContext = (context as IObjectContextAdapter).ObjectContext;

                var cats = objectContext.CreateQuery<DbDataRecord>(sql);

                foreach (var cat in cats)

                {

                    Console.WriteLine("Category '{0}' has an average price of {1}",

                    cat["CategoryName"], ((decimal)cat["AveragePrice"]).ToString("C"));

                }

            }

            // with LINQ

            using (var context = new EFRecipesEntities1101())

            {

                Console.WriteLine();

                Console.WriteLine("Using LINQ for the query...");

                Console.WriteLine();

                var cats = from c in context.Categories

                           select new

                           {

                               Name = c.CategoryName,

                               AveragePrice = MyFunctions.AverageUnitPrice(c)

                           };

                foreach (var cat in cats)

                {

                    Console.WriteLine("Category '{0}' has an average price of {1}",

                    cat.Name, cat.AveragePrice.ToString("C"));

                }

            }

        }

    }

 

    public class MyFunctions

    {

        [EdmFunction("EFRecipesModel1101", "AverageUnitPrice")]

        public static decimal AverageUnitPrice(Category category)

        {

            throw new NotSupportedException("Direct calls are not supported!");

        }

    }

Listing 11-2.用 “模型定義” 的AverageUnitPrice()函數插入和查詢模型

 

輸出結果如下麵的 Listing 11-2所示: 


 

Using eSQL for the query...

 

Category 'Backpacking Tents' has an average price of $79.99

Category 'Family Tents' has an average price of $159.99

 

Using LINQ for the query...

 

Category 'Backpacking Tents' has an average price of $79.99

Category 'Family Tents' has an average price of $159.99 


 

它是如何工作的?

“模型定義”的函數,在概念層創建,並且用eSQL來寫. 當然, “模型定義”允許你引用你模型中的實體,就像我們這裡做的這樣,在函數的實現中引用了Category 實體和Product 實體以及它們之間的關係。函數帶來的額外好處是:我們不會被綁定在一個指定的存儲層上。把函數放在更低的層,甚至是資料庫驅動, 我們的程式也可以工作.

目前的設計器不支持“模型定義”函數,不像存儲過程,能被設計器支持,“模型定義”函數不會被模型瀏覽器顯示也不會出現在設計器的其它地方。設計器也不會檢查eSQL中的語法錯誤,只有在運行時才會報錯,但至少可打開.edmx來定義。

在Listing 11-2,代碼先插入兩個類別(category)和各自的一些產品(product).之後用兩種略微不同的方式查詢這些數據。在第一個查詢例子,我們創建eSQL語句來調用AverageUnitPrice() 函數.並執行查詢. 在查詢結果中的每行,我們取出第一列數據(category名稱)和第二列數據(每個類別產品的平均單價). 並且輸出。

第二個查詢例子,更有趣,我們在LINQ查詢中使用AverageUnitPrice()函數,不過需要先在另一個類里添加一個方法存根,方法用 [EdmFunction()] 特性裝飾, 把它標記為是一個“模型定義”函數. 運行時方法不可以調用它(一旦調用,方法中就顯式拋出異常). 因為我們只是返回一個標量值,所以這個方法簽名比較簡單(參數個數,類型,和返回值類型). 在In the LINQ 查詢中query, 我們獲取每個category並且把結果(category名稱,調用MyFunction類里AverageUnitPrice()方法返回的結果)映射到一個匿名類. 並且輸出。

DbContext是 ObjectContext輕量級的版本. 每當需要執行eSql (Entity SQL)時, 是必須使用ObjectContext 的. 因為我們要通過DbContext獲取ObjectContext (使用:(context as IObjectContextAdapter) ObjectContext).

“模型定義”函數的參數可以是:標量值,實體類,複雜類型,匿名類型,或是上述類型的集合).在本章的很多小節,我們就演示如何創建和使用這些類型參數的“模型定義”函數。

“模型定義” 函數的參數沒有方向性,沒有“輸出”參數,只有“輸入”參數,原因是“模型定義” 函數只是一個”組件”,並且能成為LINQ查詢的一部分。

在這個例子中,我們返回單一的標量decimal類型的值。因為Select查詢結果會被理解成一個集合,所以我們需要為返回的結果顯式地使用AnyElement運算符。EF不知道如何把一個集合映射成一個標量值,所以我們在這兒使用AnyElement運算符告訴它返回的結果只是一個元素。當Select結果只有一個元素的時候,我們也會運用該運算符告訴調用者它只是一個元素。

最佳實踐

“模型定義”函數提供了一個純凈和有效的概念模型的組成部分.下麵列幾個它的最佳實踐:.

>“模型定義”函數用eSQL 定義到概念層. 這使用我們可以從存儲模型細節中抽象出一個更完成的模型.

>你可以把LINQ或eSQL查詢中常用的表達定義成函數. 這樣使代碼組織結構更好並且可復用. 當然,如果使用LINQ, VS提供的智能感知和編譯時檢查,會讓代碼減少因為誤輸入帶來的問題.

>“模型定義”函數是一個”組件”,允許你把它當成一個組成部分用在更複雜的表達式中. 這樣可以合你代碼更簡單些,並具可維護性.

>“模型定義”函數能被用在有需要計算的地方,比如一個需要計算的屬性,當實體被實例化會帶來計算的消耗,不管你用沒用到這個屬性,而“模型定義”函數只是在你確實用到這個屬性時,它才去計算這個屬性值.

 

附:創建示例用到的資料庫的腳本文件

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • A few days ago, I have tried to write bare medal program but failed. Now I find that the main mistake is that I have mistake the address of GPIO of BC...
  • 所謂的處理器就是電腦的核心運算硬體,現在使用windows操作系統的用戶使用的機器之中的處理器多數都是X86內核,而實際之上很多時候我們用戶都是會在心目之中把一個處理器和其運行的特定操作系統掛鉤,之前說的X86和windows操作系統,而在Cortex-A系列硬體之上我們運行的多數都是Androi...
  • 1,使用工具概述 FT232Rl晶元+sscom32+示波器 2,接收數據分析 sscom32發送數據:0xaa[1010 1010] 波特率為:4800bps @5V系統 示波器測試FT232RL 發送引腳 Txd,得到數據如上圖所示。 從上圖中可以得到如下幾點結論: 1.Txd空閑為高電平。 2...
  • 1.修改主機名及hosts文件10.205.22.185 nn1 (主)作用namenode,resourcemanager,datanode,zk,hive,sqoop10.205.22.186 nn2 (備)作用namenode,resourcemanager,datanode,zk10.205...
  • BBB 的板上有五個 LED 燈,一個電源,四個其他指示燈,usr0 至 usr3 。這次學習是控制 usr0 至 3 讓它們亮著,熄滅,閃。算是個 Hello World 實驗。非常簡單。 需要的材料: BBB 一臺 購買BBB 自帶的數據線一條 手提電腦或台式電腦,有 USB 插頭的 首先用數據...
  • 由於Python易學、開源、面向對象、可移植性高、庫豐富的特點,近期開始學習Python。百度瞭解了各款Python IDE後,還是認為Eric比較適合我,所以踏上了安裝Eric坎坷之路,從選定工具到安裝成功一共花費了8天時間,從Windows到Linux再到Mac,挨個折騰了一遍,Windows的...
  • 問題一:什麼是C#?C#是微軟公司在2000年新推出的一款運行在.NET Framework平臺上面的編程語言,這個.NET Framework平臺又怎麼去理解呢?舉個例子來說好了,一個土著族人只會說土著話,他跑到美國去用土著話跟別人交流,別人當然什麼都聽不懂,最後他還是乖乖回到他的土著國。那麼在這...
  • 此文主要分享瞭如何將自己博客園的文章自動導出到 Markdown 文檔進行存儲,以便在本地進行歸檔管理,程式中也對文章的分類、tag、代碼塊以及文章中的圖片進行了保存處理,以便上傳到自己的圖床。
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...