[C#][EF] Code First From Database (二) DbContext

這一篇將檢視DbContext的內容
並確認連線字串設定是否正確
Continue reading “[C#][EF] Code First From Database (二) DbContext"

廣告

[C#][EF] Find & FirstOrDefault

這篇將做個小實驗
關於Entity Framework的查詢運算式
使用FindFirstOrDefault的差異


首先是關於Find的說明:DbSet.Find方法
可以看到它的查詢條件限定於Primary Key
並且是先從Cache中查詢
如果查不到,才到Database去查詢

所以若是查詢目標在Cache的狀況下,Find的效能是最快的
接著使用中文北風資料庫來測試一下

static void Main(string[] args)
{
    EFEntities ef = new EFEntities ();

    int id = 2;
    for (int i = 0; i < 5; i++)
    {
        var find = ef.產品資料.Find(id);
        Console.WriteLine(find.產品);
    }
    Console.ReadKey();
}

上方程式碼進行了5次的Find
但透過SQL Server Profiler
可以看到實際只進行1次查詢 (其餘4次直接從Cache拿到結果)

2017-3-10 下午 05-18-42

再來試試FirstOrDefault

static void Main(string[] args)
{
    EFEntities ef = new EFEntities();

    int id = 2;
    for (int i = 0; i < 5; i++)
    {
        var firstOrDefault = ef.產品資料.FirstOrDefault(x=> x.產品編號 == id);
        Console.WriteLine(firstOrDefault.產品);
    }
    Console.ReadKey();
}

結果如下,5次都會對Database進行查詢

2017-3-10 下午 05-25-57


結論:

[C#] 初探Entity Framework (九) – 關聯式查詢

這篇文章將介紹關聯式查詢
參考以下兩篇文章

範例將使用Northwind中的兩張Table: Orders, Customers,如下圖

2017-2-16-%e4%b8%8b%e5%8d%88-06-01-52

範例:從Orders關聯查詢Customers中的CompanyName, ContactName
首先使用SQL進行Table Join的查詢

2017-2-16 下午 06-09-05.png

接著換用Entity Framework來試試看
寫法如下圖,使用Include進行關聯查詢
之後就可以直接取得關聯表的欄位值

2017-2-16-%e4%b8%8b%e5%8d%88-06-28-04

輸出結果如下圖,完成!

2017-2-16-%e4%b8%8b%e5%8d%88-06-26-54

[C#] 初探Entity Framework (八) – Transaction

這篇簡單實作Entity Framework的Transaction使用方式

2016.11.08修正

一般寫asp.net時,通常一個DBContext用完即丟
參考:Entity Framework DbContext 物件的生命週期 – Huan-Lin學習筆記

不過我目前是開發Winform專案
User 之間本身就是隔離的獨立個體
因此有時會重複使用DBContext
好處是可以善用快取、追蹤、交易管理等功能

交易處理的參考網頁:Working with Transactions (EF6 Onwards)
簡單的實作方法如下

public void UploadToDB(EFEntities ef)
{
    using (DbContextTransaction tran = ef.Database.BeginTransaction())
    {
        try
        {
            //暫時取消AutoDetect,提高新增資料的效率
            ef.Configuration.AutoDetectChangesEnabled = false; 
            
            //這邊自行撰寫,對你的資料庫進行新增、修改、刪除等工作
            ef.SaveChanges();

            tran.Commit(); //成功SaveChange後,才讓此交易成立
            MessageBox.Show("上傳完成");
        }
        catch (Exception ex)
        {
            MessageBox.Show("上傳錯誤,將顯示錯誤訊息");
            MessageBox.Show(ex.ToString());
            tran.Rollback();//SaveChange失敗,取消此交易動作
        }
        finally
        {
            ef.Configuration.AutoDetectChangesEnabled = true;
        }
    }
}

 

[C#] 初探Entity Framework (七) – Update, Delete

這篇介紹UpdateDelete
方法其實和Insert大同小異

首先介紹Update,原始Table如下圖
2016-3-4 下午 06-02-33.png

目標嘗試把EmployeeID大於5的人們,將他的City改成Taipei

SQL語法如下
UPDATE Northwind.dbo.Employees
SET City = ‘Taipei’
WHERE EmployeeID > 5

使用EF的範例Code如下

        private void btn_Update_Click(object sender, EventArgs e)
        {
            IQueryable<Employees> result = ef.Employees.Where(x => x.EmployeeID > 5);

            foreach (Employees em in result)
            {
                em.City = "Taipei";
            }
            ef.SaveChanges();
        }

成功的結果如下圖
2016-3-4 下午 06-08-23.png


 

接下來是Delete,就試試把City不是Taipei的人們刪除吧!
範例Code如下

private void btnDelete_Click(object sender, EventArgs e)
        {
            IQueryable<Employees> result = ef.Employees.Where(x => x.City != "Taipei");

            foreach (Employees em in result)
            {
                ef.Employees.Remove(em);
            }
            ef.SaveChanges();
            MessageBox.Show("Finish");
        }

成功結果
2016-3-4 下午 06-14-56

另外這邊做個提醒
如果即將刪除的項目,有被關聯到其他Table作為外來鍵
可能會產生無法刪除的狀況
這邊為了測試方便,有先把Norwind.dbo.Employee的關聯性先拿掉

若想直接連帶刪除的話
可以參考這篇文章
ADO.Net Entity Framework : (十六) 關聯式資料 – 刪除


下一篇:[C#] 初探Entity Framework (八) – Transaction

[C#] 初探Entity Framework (六) – Insert, Bulk Insert

這篇介紹Insert的方法

下圖是範例使用的目標Table: Employees
2016-3-2 下午 05-00-42.png
接著我要Insert “Chris Jheng" 到Employees之中

private void btnInsert_Click(object sender, EventArgs e)
        {
            Employees newOne = new Employees();
            newOne.LastName = "Chris";
            newOne.FirstName = "Jheng";

            ef.Employees.Add(newOne);
            ef.SaveChanges();

            MessageBox.Show("Finish");
        }

成功的結果如下圖
2016-3-2 下午 05-12-56


接下來是關於BulkInsert的問題
由於Entity Framework並沒有MS SQL的DataTable BulkCopy功能
因此必須一個一個Insert進去
而在這樣的狀況下,大量Insert時的效能就很差
範例Code如下

private void btnBulkInsert_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < 2000; i++)
            {
                Employees newOne = new Employees();
                newOne.LastName = "Last_" + i.ToString();
                newOne.FirstName = "First_" + i.ToString();

                ef.Employees.Add(newOne);               
            }

            ef.SaveChanges();

            MessageBox.Show("Finish");
        }

測試Insert 2000筆資料,花了大約30秒,效能分析如下圖
2016-3-2 下午 05-41-15.png
效能分析的使用方法,可以參考這篇Performance Analysis
從上圖可以看到效能瓶頸卡在DetectChanges
再查一下Code可以找到原因,是由於每一次Add新物件,EF都會自動DetectChanges
2016-3-2 下午 05-46-01.png

我們把這個功能關掉看看
加入這行:ef.Configuration.AutoDetectChangesEnabled = false;

        private void btnBulkInsert_Click(object sender, EventArgs e)
        {
            ef.Configuration.AutoDetectChangesEnabled = false;

            for (int i = 0; i < 2000; i++)
            {
                Employees newOne = new Employees();
                newOne.LastName = "Last_" + i.ToString();
                newOne.FirstName = "First_" + i.ToString();

                ef.Employees.Add(newOne);               
            }

            ef.SaveChanges();

            MessageBox.Show("Finish");
        }

結果如下,這次花費約12秒完成,節省一半以上的時間。

2016-3-2 下午 05-49-51.png


小提醒
雖然這個方法可以稍微改良Bulk Insert的效能問題
但和MS SQL的BulkCopy功能相比,速度還是相差太多
因此可以考慮使用其他套件來解決此問題
例如:EntityFramework.BulkInsert
或者是使用組合字串的方式,也可以暫時解決此問題

 

下一篇:[C#] 初探Entity Framework (七) – Update, Delete

[C#] 初探Entity Framework (五) – Join Table

這篇將承接[C#] 初探Entity Framework (四) – Select
介紹Join Table的方法

範例使用的來源Table如下

  • Table: Orders
    2016-3-2 下午 03-40-14.png
  • Table: Employees
    2016-3-2 下午 03-41-05.png

範例:Join Table

由於Join Table的語法較長,這邊我會使用Linq的寫法,可讀性較高

private void JoinTable_Click(object sender, EventArgs e)
{
    var result = (from order in ef.Orders
                  join eployee in ef.Employees on order.EmployeeID equals eployee.EmployeeID
                  orderby order.OrderID
                  select new { order.OrderID, order.CustomerID, order.EmployeeID, 
                               eployee.LastName, eployee.FirstName }).Take(10);
                     
    foreach (var x in result)
    {
        Console.WriteLine(x.OrderID + ", " + x.CustomerID + ", " 
                        + x.EmployeeID + ", " + x.LastName + " " + x.FirstName );
    }
}

結果如下,成功Join了兩張Table。
2016-3-2 下午 04-00-45.png


題外話,我會盡量把需要Join的Table
直接在Database建立View使用
而若是有更加複雜的查詢
也可以建立FunctionStore Procedure
確保查詢語法的效能強度
(避免Entity Framework自動產生效能較差的查詢語句)

 

下一篇:[C#] 初探Entity Framework (六) – Insert, Bulk Insert

[C#] 初探Entity Framework (四) – Select

這篇文章將介紹如何從Entities進行查詢動作

首先可以參考David.Net的文章
ADO.Net Entity Framework : (十八) 介紹 EF 提供的三種查詢方式
其中介紹了LinqLambda的查詢寫法

我是習慣使用Lambda的寫法,也覺得較為簡潔
以下進行簡單的範例介紹

範例將使用Northwind中的Table:Employees,如下圖

2016-3-1 下午 04-42-54

(使用Lambda語法前,請記得using System.Linq;)



範例1:取得所有項目

        private void SelectAll(NorthwindEntities ef)
        {
            var result = ef.Employees.Select(x => x);            
        }

是的,您沒看錯,只需要一行就解決
這樣就取得了資料庫中Employees中的所有內容

下一步我會把語法蜜糖var給修掉,加強可讀性
(滑鼠移上去就能看到目前的型態)

        private void SelectAll(NorthwindEntities ef)
        {
            IQueryable<Employees> result = ef.Employees.Select(x => x);            
        }

再來驗證一下結果吧
foreach把 EmployeeID, LastName, FirstName三個欄位吐出來

 private void SelectAll(NorthwindEntities ef)
        {
            IQueryable<Employees> result = ef.Employees.Select(x => x);
            foreach (Employees em in result)
            {
                Console.WriteLine(em.EmployeeID + "," + em.LastName + " " + em.FirstName);
            }
        }

結果如下,完成。
2016-3-1 下午 04-38-49.png


範例2:取得特定項目 (Where)

這次試著取得Country = USA的項目,並且只取用FirstName的部分
順便再轉成List<string>的型態
程式碼如下

   private void SelectUSA(NorthwindEntities ef)
        {
            List<string> result = ef.Employees.Where(x => x.Country == "USA")
                                              .Select(x => x.FirstName).ToList();
            foreach (string name in result)
            {
                Console.WriteLine(name);
            }
        }

結果如下,可以和上面第一張表對照

2016-3-1 下午 04-57-06


 

Select的範例介紹到這邊
另外在查詢語法也有Distinct, First (or Default), Join, ToArray……等其他常用的語法
請再依需求搭配使用囉!

 

下一篇:[C#] 初探Entity Framework (五) – Join Table