標籤:
在上一節中,實現了CodeFirst快速入門。但是很多與資料庫的細節還無法自訂。以及使用EF過程中,需要注意的事項。
在本節中,會涉及到以下
- EF中的連接字串
- EF的對象狀態
- 消極式載入,為什麼需要Virtual,貪婪載入
- 繞過EF,直接SQL查詢
- 查看EF產生SQL語句
- 實體與資料庫的映射通過DataAnnotation與FluentAPI兩種方式
- 結合MVC非同步控制器做個CRUD例子
- 建議
連接字串
1個完整的連接字串 IP:連接埠\執行個體名 資料庫名組成
Nuget安裝完EF會在*.config的entityFramework節點下添加,表示使用LocalDb資料庫,執行個體名為v11.0。
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework"> <parameters> <parameter value="v11.0" /> </parameters></defaultConnectionFactory>
而資料庫名,預設為類的全限定名。如下調用父類建構函式,表示資料庫名為SaleDb。而不是命名空間+類名。
public class SaleDb : DbContext { public SaleDb():base("SaleDb") { } }
當然,在這個建構函式裡,可以完整的寫上完整的連接字串。
EF的對象狀態
db.Entry(TEntity).State (附加Entity,並設定狀態)
public enum EntityState { // 摘要: // The entity is not being tracked by the context. An entity is in this state // immediately after it has been created with the new operator or with one of // the System.Data.Entity.DbSet Create methods. Detached = 1, // // 摘要: // The entity is being tracked by the context and exists in the database, and // its property values have not changed from the values in the database. Unchanged = 2, // // 摘要: // The entity is being tracked by the context but does not yet exist in the // database. Added = 4, // // 摘要: // The entity is being tracked by the context and exists in the database, but // has been marked for deletion from the database the next time SaveChanges // is called. Deleted = 8, // // 摘要: // The entity is being tracked by the context and exists in the database, and // some or all of its property values have been modified. Modified = 16, }
消極式載入,貪婪載入,為什麼需要Virtual
消極式載入(lazy load)是(也稱為懶載入),消極式載入機制是為了避免一些無謂的效能開銷而提出來的,所謂消極式載入就是當在真正需要資料的時候,才真正執行資料載入操作。可以簡單理解為,只有在使用的時候,才會發出sql語句進行查詢。
貪婪載入則是一次性把相關的表也載入進來。
在EF中,預設是支援消極式載入的。
db.Configuration.LazyLoadingEnabled = false; //設定禁用消極式載入
如果想單個貪婪載入某個表。則通過Include("表名")
db.Orders.Include("OrderItems"); //把OrderItems表一併載入進來
Virtual關鍵字
通常相關連的表作為Entity屬性的時候,使用Virtual關鍵字修飾符。如果不加Virtual關鍵字,則關聯的類只是一個普通的POCO類型。get,set方法為空白實現。
使用Virtual關鍵字後,EF產生一個代理類來重寫get和set方法。實現需要的功能。
繞過EF,直接SQL查詢
EF作為一個架構,也不可能做到滿足所有需求。EF提供了直接操作Ado.net方式。
有三個 API 支援:
- DbContext.Database.ExecuteSqlCommand
- DbContext.Database.SqlQuery
- DbSet.SqlQuery
執行sql 返回受影響函數。
public int ExecuteSqlCommand(string sql, params object[] parameters);
執行sql 返回查詢結果並自動對應到指定類上。(不會被EF跟蹤狀態)
DbRawSqlQuery<TElement> SqlQuery<TElement>(string sql, params object[] parameters);
執行sql 返回查詢結果並自動對應到指定類上。(被EF跟蹤狀態。DbSqlQuery繼承自DbRawSqlQuery)
virtual DbSqlQuery<TEntity> SqlQuery(string sql, params object[] parameters);
查看EF產生SQL語句
當使用EF執行一個複雜的查詢時候。我們需要知道EF是否按照我們所需執行。這時,就需要查看EF產生的語句。
- 執行IQueryable<T>.ToString(); 即可查看產生的sql語句。
- 通過EFProviderWrappers,這裡不做贅述。
DataAnnotation
DataAnnotation 特性由.NET 3.5中引進,給.NET中的類提供了一種添加驗證的方式。同時在EF中,也是添加約束與個人化一種方式。
常用到以下特性。
- KeyAttribute:對應資料庫中的主鍵
- RequiredAttribute:對應資料庫中欄位的資料是否可以為null
- MaxLengthAttribute:對應資料庫中字串類型欄位的最大長度
- MinLengthAttribute:在資料庫中無對應,但在代碼中字串最小長度
- TimestampAttribute:將列的資料類型指定為行版本
- DatabaseGeneratedAttribute:標記指定實體屬性是由資料庫產生的,並指定建置原則(None資料庫不產生值,Identity當插入行時,資料庫產生值,Computed當插入或更新行時,資料庫產生值)
- ColumnAttribute:指定實體屬性在資料庫中的列名及資料類型
- TableAttribute:指定實體類對應的資料表名
- ForeignKeyAttribute:指定導覽屬性的外鍵欄位
- NotMappedAttribute:標記指定實體屬性在建立資料庫中不建立對應欄位
- ConcurrencyCheck:並發標記
public class Order { [Key] public int Id { get; set; } [StringLength(200)] public string Name { get; set; } public int UserId { get; set; } [ForeignKey("UserId")] public User User { get; set; } public virtual ICollection<OrderItem> OrderItems { get; set; } }
FluentAPI
使用DataAnnotation(DA)非常方便,但有時我們的POCO類不希望受到EF的直接關聯。或者DA不能滿足需求。這時,我們可以使用FluentAPI方式。
- HasKey - KeyAttribute:配置此實體類型的主鍵屬性
- IsRequired - RequiredAttribute:將此屬性配置為必需屬性。用於儲存此屬性的資料庫列將不可以為null
- HasMaxLength - MaxLengthAttribute:將屬性配置為具有指定的最大長度
- IsConcurrencyToken - ConcurrencyCheckAttribute:將屬性配置為用作開放式並發標記
- IsRowVersion - TimestampAttribute:將屬性配置為資料庫中的行版本。實際資料類型將因使用的資料庫提供者而異。將屬性設定為行版本會自動將屬性配置為開放式並發標記。
protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity<AppInfo>().Property(o => o.Id).HasColumnName("AppId"); }
MVC非同步控制器做個CRUD例子
微軟自家的東西關聯總是那麼方便。
在MVC5中,添加控制器的時候選擇使用EF即自動產生這一切。
建議
1.模型改變重建資料庫,導致表資料丟失。
在使用CodeFirst中,當模型改變的時候,採用第一節中的Nuget中EF Migration API方式則不會清空資料。
2.是否使用預存程序,視圖這些資料庫技術。
當使用EF 這種ORM架構的時候,就應該輕資料庫技術,重商務邏輯層。我的建議是萬不得已不要使用預存程序,視圖實際只是儲存了SQL語句。
MVC5代碼下載:MVCTest
[ORM] Entity Framework(2) CodeFirst進階