一.模型级查询过滤器(Model-level query filters)
ef core2.0包含了一个新特性,我们叫他模型级查询过滤器(Model-level query filters)。此特性允许使用Linq查询表达式直接定义在实体类型的元数据模型上。这样的过滤器会自动应用到任何LINQ查询所涉及的那些实体类型,包括间接引用的实体类型(对象引用,导航属性)。这个特性的一些常见应用是:
软删除-定义一个 IsDeleted 属性
多租户-定义一个 TenantId 属性
示例代码:
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
public int TenantId {get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Post>().HasQueryFilter(
p => !p.IsDeleted
&& p.TenantId == this.TenantId );
}
}
我们给 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)这种机制可以绕过缓存查找的性能消耗,直接调用已经编译好的表达式,获得一个小的性能提升。
示例代码:
// Create an explicitly compiled query
private static Func<CustomerContext, int, Customer> _customerById =
EF.CompileQuery((CustomerContext db, int id) =>
db.Customers
.Include(c => c.Address)
.Single(c => c.Id == id));
// Use the compiled query by invoking it
using (var db = new CustomerContext())
{
var customer = _customerById(db, 147);
}
四.在使用FromSql和ExecuteSqlCommand方法时加入参数化查询
在使用C#6.0的特性构建SQL语句并使用FromSql和ExecuteSqlCommand方法执行SQL语句时,会自动加入使用参数化查询,防止SQL注入。
示例代码:
var city = "London";
var contactTitle = "Sales Representative";
using (var context = CreateContext())
{
context.Set<Customer>()
.FromSql($@"
SELECT *
FROM ""Customers""
WHERE ""City"" = {city} AND
""ContactTitle"" = {contactTitle}")
.ToArray();
}
上面的代码生成的SQL:
@p0='London' (Size = 4000) @p1='Sales Representative' (Size = 4000)SELECT *FROM ""Customers""WHERE ""City"" = @p0AND ""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类型识别,所以必须从另一个实体类型导航到它。包含定义导航的实体是所有者。当查询所有者时,默认将包含所属的类型。
按照惯例,将为所属类型创建一个影子主键,它将通过使用表拆分映射到与所有者相同的表。
示例代码:
modelBuilder.Entity<Order>().OwnsOne(p => p.OrderDetails, cb =>
{
cb.OwnsOne(c => c.BillingAddress);
cb.OwnsOne(c => c.ShippingAddress);
});
public class Order
{
public int Id { get; set; }
public OrderDetails OrderDetails { get; set; }
}
public class OrderDetails
{
public StreetAddress BillingAddress { get; set; }
public StreetAddress ShippingAddress { get; set; }
}
public class StreetAddress
{
public string Street { get; set; }
public string City { get; set; }
}
八.函数映射
EF支持映射数据库中定义的函数,可以在LINQ查询中使用。
需要在 DbContext 中定义一个静态方法,并且使用 DbFunctionAttribute 特性。
示例代码:
public class BloggingContext : DbContext
{
[DbFunction]
public static int PostReadCount(int blogId)
{
throw new Exception();
}
}
这样的方法是自动注册。一旦注册了方法,您就可以在查询的任何地方使用它。
要注意的几件事:
按照惯例,在生成SQL时,该方法的名称用作函数的名称(在本例中是用户定义的函数),但可以在方法注册期间重写名称和schema。
目前只支持标量函数
EF Core迁移将不负责创建它,您必须在数据库中创建映射函数
九.code first 实体配置
在EF6可以通过 EntityTypeConfiguraiton 封装特定实体类型的配置代码,在EF Core2.0中,这个特性回来了(EF Core 之前的 core版本不支持)。
示例代码:
class CustomerConfiguration : IEntityTypeConfiguration<Customer>
{
public void Configure(EntityTypeBuilder<Customer> builder)
{
builder.HasKey(c => c.AlternateKey);
builder.Property(c => c.Name).HasMaxLength(200);
}
}
...
// OnModelCreating
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:
public class MyDesignTimeServices : IDesignTimeServices
{
public void ConfigureDesignTimeServices(IServiceCollection services)
{
services.AddSingleton<IPluralizer, MyPluralizer>();
}
}
public class MyPluralizer : IPluralizer
{
public string Pluralize(string name)
{
return Inflector.Inflector.Pluralize(name) ?? name;
}
public string Singularize(string name)
{
return Inflector.Inflector.Singularize(name) ?? name;
}
}
本人英语水平有限,如有翻译不对的地方,欢迎批评指正。
原文地址:http://www.cnblogs.com/stulzq/p/7366044.html
.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注