Entity Framework Core 2.0 新特性

一.模型级查询过滤器(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 }

本人英语水平有限,如有翻译不对的地方,欢迎批评指正。

如果你觉得写的不错,请点一下的“推荐”,这是对我分享技术经验的支持,谢谢!

声明:原创博客请在转载时保留原文链接或者在文章开头加上本人博客地址,如发现错误,欢迎批评指正。凡是转载于本人的文章,不能设置打赏功能,如有特殊需求请与本人联系!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏【转载】DRF+Vue+Mysql_生鲜超市系统

五、商品列表页

在goods文件夹下面新建view_base.py,为了区分django和django rest framework的view

370
来自专栏SDNLAB

OpenDaylight开发-DataStoreChange监听器三种类型

OpenDaylight中的所有数据都保存在DataStore中,并且数据以树形结构存储,可参考OpenDaylight开发中的介绍。外界对DataStore的...

32610
来自专栏Java3y

从零开始写项目第三篇【在线聊天和个人收藏夹】

在线聊天 在浏览网页的时候无意发现了弹幕这个玩意,于是我们简单去探究了一下弹幕其实是怎么产生的。 后来就接触到了“推送”这么一个概念,然后发现了goEasy这个...

36511
来自专栏MasiMaro 的技术博文

hook键盘驱动中的分发函数实现键盘输入数据的拦截

我自己在看《寒江独钓》这本书的时候,书中除了给出了利用过滤的方式来拦截键盘数据之外,也提到了另外一种方法,就是hook键盘分发函数,将它替换成我们自己的,然后再...

662
来自专栏有趣的django

Django REST framework+Vue 打造生鲜超市(四)

五、商品列表页 5.1.django的view实现商品列表页 (1)goods/view_base.py 在goods文件夹下面新建view_base.py,为...

1.2K9
来自专栏闻道于事

JFinal极速开发框架使用笔记(三) 分析Model和ActiveRecord

JFinal框架的一些新发现的用法: 在JFinal框架中,实体类并不需要设置属性,更不需要配置getset方法就可以很方便的操作数据库,如果需要设置或者获取属...

3428
来自专栏debugeeker的专栏

用xerces-c来进行xml schema校验

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xuzhina/article/detai...

421
来自专栏Android源码框架分析

Android窗口管理分析(4):Android View绘制内存的分配、传递、使用

前文Android匿名共享内存(Ashmem)原理分析了匿名共享内存,它最主要的作用就是View视图绘制,Android视图是按照一帧一帧显示到屏幕的,而每一帧...

2013
来自专栏企鹅号快讯

探索Android架构组件Room

文:栋栋 本文原创,转载请注明作者及出处 一、简介 Room是Google推出的Android架构组件库中的数据持久化组件库, 也可以说是在SQLite上实现的...

3035
来自专栏MasiMaro 的技术博文

ATL模板库中的OLEDB与ADO

上次将OLEDB的所有内容基本上都说完了,从之前的示例上来看OLEDB中有许多变量的定义,什么结果集对象、session对象、命令对象,还有各种缓冲等等,总体上...

892

扫码关注云+社区