本文翻譯來自:https://docs.microsoft.com/en-us/ef/core/what-is-new/index
一.模型級查詢過濾器(Model-level query filters)
ef core2.0包含了一個新特性,我們叫他模型級查詢過濾器(Model-level query filters)。此特性允許使用Linq查詢表達式直接定義在實體類型的元數據模型上。這樣的過濾器會自動應用到任何LINQ查詢所涉及的那些實體類型,包括間接引用的實體類型(對象引用,導航屬性)。這個特性的一些常見應用是:
- 軟刪除-定義一個 IsDeleted 屬性
- 多租戶-定義一個 TenantId 屬性
示例代碼:
1 public class BloggingContext : DbContext 2 { 3 public DbSet<Blog> Blogs { get; set; } 4 public DbSet<Post> Posts { get; set; } 5 6 public int TenantId {get; set; } 7 8 protected override void OnModelCreating(ModelBuilder modelBuilder) 9 { 10 modelBuilder.Entity<Post>().HasQueryFilter( 11 p => !p.IsDeleted 12 && p.TenantId == this.TenantId ); 13 } 14 }
我們給 Post 實體類型定義了一個模型級查詢過濾器,實現了多租戶和軟刪除。模型級過濾器將使用正確的上下文實例中的值,即執行查詢的那個。
使用 IgnoreQueryFilters() 方法在一次查詢中禁用過濾器。
局限性:
- 過濾器只能在層次結構的根實體類型上定義
- 過濾器不允許使用導航屬性進行過濾(可以根據反饋添加此功能。)
二.數據庫上下文池(DbContextPool)
這是兩種可選擇的性能特性之一,旨在在高並發場景中提供更好的性能支持。
在 ef core 2.0 中,我們將自定義的DbContext類型注冊到DbContextPool服務中,可讓該數據庫上下文類型的實例重復使用。
示例代碼:
services.AddDbContextPool<BloggingContext>(
options => options.UseSqlServer(connectionString));
如果使用這種方法,當一個控制器請求一個DbContext的實例時,首先會檢查是否在DbContextPool存在該類型的實例,當一次請求結束后,任何狀態的DbContext實例都會被重置,且將自身加入到DbContextPool中。
這在概念上類似於ADO.NET提供的數據庫連接池,旨在節省一些DbContext實例初始化的成本。
三.顯式編譯查詢(Explicitly compiled queries)
這是兩種可選擇的性能特性之二 。
在以前的ef版本中,調用查詢api時,可以通過自動編譯並緩存編譯的結果達到一次計算多次調用,有效的提高了ef的性能,顯示編譯查詢(Explicitly compiled queries)這種機制可以繞過緩存查找的性能消耗,直接調用已經編譯好的表達式,獲得一個小的性能提升。
示例代碼:
1 // Create an explicitly compiled query 2 private static Func<CustomerContext, int, Customer> _customerById = 3 EF.CompileQuery((CustomerContext db, int id) => 4 db.Customers 5 .Include(c => c.Address) 6 .Single(c => c.Id == id)); 7 8 // Use the compiled query by invoking it 9 using (var db = new CustomerContext()) 10 { 11 var customer = _customerById(db, 147); 12 }
四.在使用FromSql和ExecuteSqlCommand方法時加入參數化查詢
在使用C#6.0的特性構建SQL語句並使用FromSql和ExecuteSqlCommand方法執行SQL語句時,會自動加入使用參數化查詢,防止SQL注入。
示例代碼:
1 var city = "London"; 2 var contactTitle = "Sales Representative"; 3 4 using (var context = CreateContext()) 5 { 6 context.Set<Customer>() 7 .FromSql($@" 8 SELECT * 9 FROM ""Customers"" 10 WHERE ""City"" = {city} AND 11 ""ContactTitle"" = {contactTitle}") 12 .ToArray(); 13 }
上面的代碼生成的SQL:
@p0='London' (Size = 4000) @p1='Sales Representative' (Size = 4000) SELECT * FROM ""Customers"" WHERE ""City"" = @p0 AND ""ContactTitle"" = @p1
五.Attach can track a graph of new and existing entities
EF Core supports automatic generation of key values through a variety of mechanisms. When using this feature, a value is generated if the key property is the CLR default--usually zero or null. This means that a graph of entities can be passed to DbContext.Attach or DbSet.Attach and EF Core will mark those entities that have a key already set as Unchanged while those entities that do not have a key set will be marked as Added . This makes it easy to attach a graph of mixed new and existing entities when using generated keys. DbContext.Update and DbSet.Update work in the same way, except that entities with a key set are marked as Modified instead of Unchanged .
六.表拆分(Table splitting)
現在可以將兩個或多個實體類型映射到同一表,其中主鍵列將被共享,每一行對應兩個或多個實體。
要使用表拆分,必須在共享表的所有實體類型之間配置標識關系(外鍵屬性構成主鍵)
示例代碼:
1 modelBuilder.Entity<Product>() 2 .HasOne(e => e.Details).WithOne(e => e.Product) 3 .HasForeignKey<ProductDetails>(e => e.Id); 4 modelBuilder.Entity<Product>().ToTable("Products"); 5 modelBuilder.Entity<ProductDetails>().ToTable("Products");
七.Owned types
一個owned實體類型可以與另一個owned實體類型共享相同的CLR類型。但是由於它不能被CLR類型識別,所以必須從另一個實體類型導航到它。包含定義導航的實體是所有者。當查詢所有者時,默認將包含所屬的類型。
按照慣例,將為所屬類型創建一個影子主鍵,它將通過使用表拆分映射到與所有者相同的表。
示例代碼:
1 modelBuilder.Entity<Order>().OwnsOne(p => p.OrderDetails, cb => 2 { 3 cb.OwnsOne(c => c.BillingAddress); 4 cb.OwnsOne(c => c.ShippingAddress); 5 }); 6 7 public class Order 8 { 9 public int Id { get; set; } 10 public OrderDetails OrderDetails { get; set; } 11 } 12 13 public class OrderDetails 14 { 15 public StreetAddress BillingAddress { get; set; } 16 public StreetAddress ShippingAddress { get; set; } 17 } 18 19 public class StreetAddress 20 { 21 public string Street { get; set; } 22 public string City { get; set; } 23 }
八.函數映射
EF支持映射數據庫中定義的函數,可以在LINQ查詢中使用。
需要在 DbContext 中定義一個靜態方法,並且使用 DbFunctionAttribute 特性。
示例代碼:
1 public class BloggingContext : DbContext 2 { 3 [DbFunction] 4 public static int PostReadCount(int blogId) 5 { 6 throw new Exception(); 7 } 8 }
這樣的方法是自動注冊。一旦注冊了方法,您就可以在查詢的任何地方使用它。
要注意的幾件事:
- 按照慣例,在生成SQL時,該方法的名稱用作函數的名稱(在本例中是用戶定義的函數),但可以在方法注冊期間重寫名稱和schema。
- 目前只支持標量函數
- EF Core遷移將不負責創建它,您必須在數據庫中創建映射函數
九.code first 實體配置
在EF6可以通過 EntityTypeConfiguraiton 封裝特定實體類型的配置代碼,在EF Core2.0中,這個特性回來了(EF Core 之前的 core版本不支持)。
示例代碼:
1 class CustomerConfiguration : IEntityTypeConfiguration<Customer> 2 { 3 public void Configure(EntityTypeBuilder<Customer> builder) 4 { 5 builder.HasKey(c => c.AlternateKey); 6 builder.Property(c => c.Name).HasMaxLength(200); 7 } 8 } 9 10 ... 11 // OnModelCreating 12 builder.ApplyConfiguration(new CustomerConfiguration());
十.Pluralization hook for DbContext Scaffolding
EF Core 2.0 introduces a new IPluralizer service that is used to singularize entity type names and pluralize DbSet names. The default implementation is a no-op, so this is just a hook where folks can easily plug in their own pluralizer.
Here is what it looks like for a developer to hook in their own pluralizer:
1 public class MyDesignTimeServices : IDesignTimeServices 2 { 3 public void ConfigureDesignTimeServices(IServiceCollection services) 4 { 5 services.AddSingleton<IPluralizer, MyPluralizer>(); 6 } 7 } 8 9 public class MyPluralizer : IPluralizer 10 { 11 public string Pluralize(string name) 12 { 13 return Inflector.Inflector.Pluralize(name) ?? name; 14 } 15 16 public string Singularize(string name) 17 { 18 return Inflector.Inflector.Singularize(name) ?? name; 19 } 20 }
本人英語水平有限,如有翻譯不對的地方,歡迎批評指正。
如果你覺得寫的不錯,請點一下的“推薦”,這是對我分享技術經驗的支持,謝謝!
聲明:原創博客請在轉載時保留原文鏈接或者在文章開頭加上本人博客地址,如發現錯誤,歡迎批評指正。凡是轉載於本人的文章,不能設置打賞功能,如有特殊需求請與本人聯系!