Категории: Все

по 余小章 's 5 лет назад

5375

Entity Framework

在一次討論中,參與者深入探討了如何快速開發和存取資料庫的應用程式,並分享了多種編程技巧來減少硬编码,提升代码的可维护性和效率。會議內容涵蓋了不同的Object-Relational Mapping(ORM)解決方案,包括Entity Framework、LINQ to SQL和Dapper,並詳細說明了每種工具的優點和使用方法。此外,還介紹了幾個實用的SQL工具,以幫助開發者更高效地進行資料庫操作。

Entity Framework

名詞

POCO

Plain Old CLR Objects

DTO

Data Transfer Object

Floating topic

這個Conversation沒有什麼?

點心、飲料
氣氛美好的燈光
不是速成班,內化要靠自己

這個Conversation有什麼?

要有心理準備,今天可能講不完
希望不是只是我在嘴砲,大家都能夠動手練習
幾個不錯用的SQL工具
Live Demo / Demo Code Download
幾個寫程式的小技巧,減少Hard Code
快速開發存取資料庫的應用程式

Object-Relational Mapping

SQL Server Express LocalDB

參考資料
Microsoft SQL Server 2012 Express下載與安裝
SqlLocalDB 深入剖析
SqlLocalDB 的限制(Limitations)
連接字串
Server=(LocalDB)\v11.0; Integrated Security=true; AttachDbFileName=D:\Data\MyDB1.mdf
Server=(localdb)\v11.0;Integrated Security=true
資料庫實體存放位置
系統資料庫檔案、錯誤紀錄、紀錄追蹤、加密金鑰
%userprofile%
執行個體
資料存放位置

%LOCALAPPDATA%\Microsoft\Microsoft SQL Server Local DB\Instances

手動建立執行個體

"C:\Program Files\Microsoft SQL Server\120\Tools\Binn\SqlLocalDB.exe" create "v12.0"

"C:\Program Files\Microsoft SQL Server\110\Tools\Binn\SqlLocalDB.exe" create "v11.0"

自動執行個體,安裝完SqlLocalDB後,會幫我們啟用

理論上 2014 應該是 v12.0,但事實上是MSSQLLocalDB

v11.0 代表 2012

SqlLocalDB.exe 工具
範例

建立執行個體 SqlLocalDB.exe Projects

查看 Projects 執行個體資訊 SqlLocalDB.exe info Projects

查看已安裝版本 SqlLocalDB.exe versions

路徑

2014 %PROGRAMFILES%\Microsoft SQL Server\120\LocalDB\Binn

2012 %PROGRAMFILES%\Microsoft SQL Server\110\LocalDB\Binn

如何得到它?
獨立安裝

2014

2012

from VS2013

自動安裝2012版本

安裝 SQL Server 2012 Express 以上版本
它是什麼?
若需要可以共用執行個體
一個執行個體裡面會有自己的系統資料庫 (master, msdb, model, temp)這跟SQL SERVER一樣
在同一台主機裡,每個使用者都可以建立自己的 LocalDB 執行個體,每個執行個體都是以不同使用者身分執行的不同處理序,所以不同使用者可有同名的執行個體,執行個體完全獨立分開來
小巧,不需要安裝肥大的 SQL Server,就能擁有SQL Server資料庫環境
VS2012 起,專案範本取代 SQL CE
VS Database Project

安全性

避免在將方法公開至可能未受信任的呼叫端時傳回 IQueryable,此查詢的消費者可能會針對傳回的 IQueryable呼叫 .Include("Orders") ,以擷取查詢未打算公開的資料。將方法的傳回型別變更為 IEnumerable 並呼叫會具體化結果的方法 (例如 .ToList()),便可以避免發生此情況。
避免查詢結果過大,超過系統能夠處理的大小,使用Take()限制回傳結果
SQL Injection
凡是使用字串組合的查詢都必須要自行保護
LINQ to Entities已保護
保護連線字串
若需要動態產生連線字串,請使用EntityConnectionStringBuilder 類別,避免連線字串插入攻擊

組態檔加密

限制組態檔的存取權限

勿使用明碼儲存放在檔案或是記憶體
使用Windows驗証,沒有連線字串存取的問題
SQL Server 連接加密,使用SSL

SQL Tools

SQL Server Profiler
Sample DB
Northwind
AdventureWorks
Microsoft SQL Server Data Tools (SSDT)
其餘VS版本支援SQL 2014的狀況
VS 2013 可在Extension and Update裡下載更新支援SQL 2014
VS 2012起內建
Migration/Compare
Visual Studio 2013

Tools→Sql Server

Database Project

Redgate
Management
SSMS
dbForge Studio

dbForge Studio for MySQL

資料庫比較/轉移,需要費用 當多人維護資料庫時很重要

IntelliSense

ER Model

dbForge SQL Complete
@SSMS
@VS2013 SSDT

ORM Solution

效能
http://www.cnblogs.com/bluedoctor/p/3378683.html#_Toc369989493
...
Dapper
LINQ to SQL
NHibernate
Entity Framework
效能調效

AsNoTracking

資料變更CUD,停用自動偵測變更

context.Configuration.AutoDetectChangesEnabled = false;

無法由快取更新到資料庫

物件快取不驗證

交易

Sample Code:Transaction

TransactionScope

Complete() 認可基礎存放區交易

MySQL 提供的元件不支援 Distributed Transaction

MSDTC 需啟動

DbContextTransaction

Rollback() 回復基礎存放區交易

Commit() 認可基礎存放區交易

CRUD

關聯

刪除關聯

Sample Code:DeleteRelation

Set Null

把FK找出來設為null

行為:刪除PK,FK設為null

No Action

沒有處理 FK

POCO Proxy FK 設為 Nullable

行為:刪除PK,若未先刪除FK,跳出例外訊息

Cascade

關閉Cascade

使用Fluent API,將WillCascadeOnDelete設為false

modelBuilder.Entity<Identity>()

.HasMany(a => a.IdentityLogs)

.WithRequired(o => o.Identity).HasForeignKey(o => o.IdentityId)

.WillCascadeOnDelete(false);

POCO Proxy FK 設為必填

行為:刪除PK,一併刪除FK

載入關聯

Sample Code:RelationLoading

怎麼選擇?

不確定現階段會使用哪些關聯,選擇消極式載入,可避免一次載入太多實體,程式碼也會比較容易閱讀

但如果載入太多實體,回傳的封包就會越大,這時可切換到消極式載入

當網路有問題,可選擇積極式載入,可減少網路往返

三種載入方式

積極式載入 (Eager loading)

Load() 直接載入關聯表

Include()

var find = context.Products.Include("Orders").FirstOrDefault(o => o.Id == 1)

強型別關聯

弱型別關聯

明確式載入 (Explicitly Loading)

需要關聯資料時,不會自動載入

LazyLoadingEnabled=false

消極式載入 (Lazy Loading)

會造成網路往返頻繁

需要關聯資料時,會自動載入

LazyLoadingEnabled=true

POCO Proxy

長的跟一般POCO不一樣,會像這樣一大串 {System.Data.Entity.DynamicProxies.Student_F2D791D54B1CD734227C45D5844D1724A022D1B411B8F3E88DC3D0B554876802}

自動追蹤變更,預設啟用 context.Configuration.AutoDetectChangesEnabled

自動建立Proxy,預設啟用 context.Configuration.ProxyCreationEnabled

POCO 實體啟用消極式載入,並讓 Entity Framework 在類別中發生變更時追蹤變更

查詢

不查詢快取

如果您在唯讀情節中,並想避免將物件載入 ObjectStateManager 的額外負荷,您可以發出「非追蹤」查詢。變更追蹤可在查詢層級停用。

請注意,即便如此,停用變更追蹤可讓您有效地關閉物件快取。但是當您查詢實體時,將無法從 ObjectStateManager 提取之先前具體化的查詢結果,來略過具體化。如果您重複查詢相同內容中的相同實體,您可能會實際目睹啟用變更追蹤的效能優點。

使用 ObjectContext 進行查詢時,ObjectQuery 和 ObjectSet 執行個體會記住設定的 MergeOption,且針對這些執行個體撰寫的查詢將繼承上層查詢的有效 MergeOption。使用 DbContext 時,可透過在 DbSet 上呼叫 AsNoTracking() 修飾詞來停用追蹤。

使用 IEnumerable.Contains<>(T value)

int[] ids = new int[10000];

...

using (var context = new MyContext())

{

var query = context.MyEntities

.Where(entity => ids.Contains(entity.Id));

var results = query.ToList();

...

}

將您的查詢連結至另一個需要重新編譯的查詢

Database.SqlQuery

var q1 = context.Database.SqlQuery<Product>("select * from products");

DbSet.AsNoTracking()

var q = context.Products.AsNoTracking().Where(p => p.Category.CategoryName == "Beverages");

查詢結果不會放入快取,可避免狀態改變而引起的額外記憶體負荷

直接對SQL做查詢

查詢快取

繫結UI

DbSet.Local

適用,資料庫主要修改權,只有單一應用程式

不會返回 EntityState.Deleted 實體

DbSet.Load() 將查詢到的資料cache到DbSet.Local

DbContext.Customers.Load();

context.Posts.Where(p => p.Tags.Contains("entity-framework").Load();

用法

DbSet.SqlQuery

var q2 = context.Products.SqlQuery("select * from products");

For迴圈

LINQ to Entities

查詢相同資料時,快取可發揮校能

第二次的查詢稱為暖查詢,查詢快取

第一次的查尋稱為冷查詢,查詢 DB 實體

存檔

DbContext.SaveChanges()

刪除

DbSet.Remove()

建立

DbSet.Add()

Three Model

如何使用?

繼承

TPH

父、子類別只產生一個Table

TPT

如果您的模型使用 TPT 繼承,產生的查詢會比使用其他繼承策略所產生的查詢更複雜,而可能導致存放區上的執行時間更長。透過 TPT 模型產生查詢及具體化產生的物件,通常需要更長的時間。

父、子類別都會產生Table,並使用主鍵共享一對一關聯

TPC

主類別不會產生Table,子類別會

Update Schema

MigrateDatabaseToLatestVersion 表示使用 Code First 移轉以將資料庫更新至最新版本之 IDatabaseInitializer 的實作。

Database.SetInitializer(new MigrateDatabaseToLatestVersion<CustomerDbContext, AppCodeFirst.Migrations.Configuration>());

步驟

Update-Database

Update-Database -Verbose 查看「Code First 移轉」所執行的 SQL

Add-Migration

Add-Migration InitialCreate -IgnoreChanges 建立空的 DbMigration,主要用來更新已存在的Database

Add-Migration AddPostAbstract 最佳猜測建立結構

Add-Migration [有意義的名稱]

Add-Migration InitialCreate 第一次執行新增資料庫移轉

Enable-Migrations

Enable-Migrations -ConnectionStringName DefaultConnection

Enable-Migrations –ContextTypeName [DbContext Class Name]

如果專案裡不只一個 DbContext 類別的話,可以原本的指令後面 DbContext 類別名稱

enable-migrations –ContextTypeName BlogSample.Models.SampleContext

Enable-Migrations -EnableAutomaticMigrations

自動轉移,只對新增欄位有效,刪除、修改無效

連線字串

讀取 Web.config/App.config

預設連接工廠

<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">

<parameters>

<parameter value="v11.0" />

</parameters>

</defaultConnectionFactory>

類型探索

資料庫初始化

Database.SetInitializer(IDatabaseInitializer strategy)

DropCreateDatabaseIfModelChanges 它只會在模型於資料庫建立後已變更時刪除及重新建立資料庫,並選擇性地重新植入資料庫。

CreateDatabaseIfNotExists 只會在資料庫不存在時重新建立資料庫,並選擇性地重新植入資料庫。 若要植入資料庫,請建立衍生類別並覆寫 Seed 方法。

DropCreateDatabaseAlways IDatabaseInitializer 的實作,只要是初次在應用程式定義域中使用內容,就一定會重新建立資料庫,並選擇性地重新植入資料庫。 若要植入資料庫,請建立衍生類別並覆寫 Seed 方法。

Database.SetInitializer(new DropCreateDatabaseIfModelChanges<SystemDbContext>());

定義DbSet 屬性

public class SystemDbContext : DbContext

{

public DbSet<Identity> Identities { get; set; }

public DbSet<Employee> Employees { get; set; }

public DbSet<Candidate> Candidates { get; set; }

public DbSet<CandidateData> CandidateDatas { get; set; }

public SystemDbContext()

: base("LocalDbConnect")

{

Database.SetInitializer(new DropCreateDatabaseIfModelChanges<SystemDbContext>());

}

}

實作DbContext,繼承 DbContext

建立POCO (Plain Old CLR Objects)

定義關聯

Fluent API

Sample Code:SimpleFluentAPI

Implement EntityTypeConfiguration

Override OnModelCreating

欄位Attribute

Sample Code:UseAttribute

System.ComponentModel.DataAnnotations

StringLength 指定資料欄位中允許的最小和最大字元長度

Required 必填欄位

MinLength 指定屬性中所允許之陣列或字串資料的最小長度

MaxLength 指定屬性中所允許之陣列或字串資料的最大長度

Key 表示唯一識別實體的一個或多個屬性

System.ComponentModel.DataAnnotations.Schema

如何定義 POCO Proxy

Sample Code:DefaultBehavior

多對多

一對多

一對一

關聯性中的「多」端的導覽屬性必須傳回會實作 ICollection 的型別

導覽(navigation)屬性必須宣告為 public、 virtual

當類別的屬性有 Id (不分大小寫)或是後綴詞含有 Id,這個欄位就會變成主索引鍵 PK,若同時有兩個欄位後綴詞帶有 Id,EF 就會自己挑一個來當 PK

預設慣例

Sample Code:SimpleCodeFirst

為什麼要用Code First

缺點

DBA 介入時會造成衝突

必須手動建立POCO

優點

聚焦在業務邏輯

開發期間不需要關心資料庫欄位是否存在 (傳統ADO.NET的做法要改兩個地方,資料庫跟程式碼)

動態建立資料庫

Source Control

彈性大,不受工具影響

Model First

Database First

Demo Database First

Environment

LocalDB

安裝 SSDT for SQL 2014(SQL Server Data Tools)

Entity Framework 6.1 from NuGet

安裝 Entity Framework 6.1.0 Tools

兩大類別

ObjectContext

DbContext

支援多種關聯性資料庫

Oracle

PostgreSQL

DB2

SQLite

Maria

MySQL

SQL Compact Edtion

SQL Server

Open Source

Main topic

變更資料型態
modelBuilder.Properties().Configure(c => c.HasColumnType("datetime2"));
關閉 Cascade
modelBuilder.Conventions.Remove();

說好的MariaDB呢?

新版EF支援有問題
Code First

在 DbContext 加上Attribute [DbConfigurationType(typeof(MySql.Data.Entity.MySqlEFConfiguration))]

組態檔

準備開發環境
安裝 ADO.NET driver for MySQL
安裝 Mariadb

架構

解偶合架構圖
Repository Pattern

業務邏輯依賴的是Repository Interface,而不是DAL的操作,當資料來源有很多不一樣的資料格式時,程式碼才不需要做變更

MVC & MVP
三層式架構
架構圖
3-Layer 名詞解釋

UI

人機介面

User Interface

Presention Layer

BLL

Business Logic Layer

DAL

Data Access Layer

ORM

物件化有什麼好處?

可透過反射或序列化,減少 Hard Code
有了反射跟序列化,再也不需要擔心欄位變更了
這個時候熬夜寫code不再需要蠻牛,而是反射或序列化
想像一下,若有100個欄位需要處理,寫到後面你會有什感覺
深複製

Sample Code:SimpleReflrction

可使用LINQ語法
Sample Code:SimpleQuery
繫結 Presentation Layer
OOP (Object-oriented programming)

為什麼要用ORM?

ORM 缺點
要怎麼提升效能?

徹底瞭解ORM的工作原理

效能提升是需要成本的

在ADO.NET裡面,讀取方式使用 DataReader+Sequential Access 最快

為什麼會損耗?

會影響效能的技術

延遲載入 (Lazy Loading) 關聯性物件,不會一次載入,待需要使用時才會動態載入 是優點也是缺點,在適當的情境下使用

SQL Generation,自動產生 SQL 指令

Attribute 宣告自訂對應

Type Converter,列舉型別轉換

Reflection,動態的對應 Property 和 Field

效能損耗
ORM 優點
Connection Pool 自我管理
自動緩存(cache)查詢,減少網路流量
Lazy Loading,消極式載入,有用到才會載入,節省流量
更容易處理關聯物件Relation
自動處理資料庫注入攻擊(SQL Injection)
自動產生 SQL 語法,程式設計師不需要瞭解各個不同的SQL語法 對架構而言已經面對物件,所以當遇到資料庫轉移或切換,不需要變更原有程式

情境: 當PM說要抽換資料庫,由原本的 Sql Server 換成 Mariai,程式會大改,你感覺如何?

動態將資料表轉換成物件(class),消除魔術字串,依賴IDE的IntelliSense,降低除錯成本

回顧一下ADO.NET怎麼寫? Sample Code:ADOConnect

降低對資料庫的學習成本,更專注在商業、業務邏輯

什麼是ORM

由『物件資料』到『關聯資料庫的存儲』對映的技術,將資料庫操作用物件導向的形式來呈現