编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

看看Entity Framework Core 2有哪些新的变化?

wxchong 2024-07-11 01:07:45 开源技术 11 ℃ 0 评论

介绍

大家都清楚,EF Core 2在8月14日发布了。它加入了一些新的东西,也对之前的内容进行了一些变化。遗憾的是,它仍然没有包含 pre-Core版本中的一些特性,而且需求很高,比如对延迟加载和Group by的支持。

我们来看看这个列表

.NET Standard 2.0

刚刚发布的Entity Framework Core 2 现在是基于.NET Standard 2.0的。这意味着它可以在很多环境中使用,只要是支持它的平台上都有用。

改进SQL生成

改进包括:

不需要嵌套子查询的时候,不会进行嵌套子查询的创建

只对需要查询的列进行映射

不会在一个LINQ查询中创建多个SQL查询了

自有实体(Owned Entities)

复杂类型回归,现在它们被称为自有实体了。请记住,复杂类型和实体之间的区别在于前者没有标识。例如,一个Address类和很多属性,Personal,Work等等;所有这些属性都可以映射到这个类,它们将被存储在与包含实体相同的表中。看起来像这个:

modelBuilder.Entity<Customer>().OwnsOne(c=>c.PersonalAddress);

当然,你也可以把这些属性的上下文放到其他的表里面,你只需要这样做:

modelBuilder.Entity<Customer>().OwnsOne(c=>c.PersonalAddress).ToTable(“CustomerAddress”);

当然,你可以一次性拥有很多属性,不过这个时候,你就无法通过属性来声明自有实体。

分表(Table Splitting)

你可以拥有多个不同的类同时指向一张表,Entity Framework Core允许你这样做。这些类可以暴露出不同的属性。

实体状态监听(Entity State Listener)

这是一个默认就被注册的新街口,ILocalViewListener,他可能用于跟踪实体的变化,但是可惜不是实例化后的实体。

varevents=ctx.GetService<ILocalViewListener>();events.RegisterView((entry,state)=>{//entrycontainstheentityandstateitscurrentstate});

在这里你需要注意,你不能够使用这个来取消改动,因为它只会在实际事件发生后才进行调用。

多元化(Pluralization)

来说一下这个新的接口 IPluralizer和它的空实现NullPluralizer。当EF生成数据库(EF更新数据库)或者生成实体并根据其生成类时(Scaffold-DbContext),它可以用于复数的表名。使用它是有难度的,我们需要有一个类实现IDesignTimeServices接口,这个类通过下面的工具自动检索:

publicclassCustomPluralizerDesignTimeServices:IDesignTimeServices{publicvoidConfigureDesignTimeServices(IServiceCollectionservices){services.AddSingleton<IPluralizer,CustomPluralizer>();}}publicclassCustomPluralizer:IPluralizer{publicstringPluralize(stringname){return...;}publicstringSingularize(stringname){return...;}}

因为工具还依赖于依赖注入框架,我们通过IPluralizer 接口进行另一种实现。

数据库上下文池(DbContext Pools)

通常当DbContext被依赖注入框架在什么地方注入后,每次将会创建一个新的实例。这样,我们可以建立一个实例的资源池,默认一个资源池可以有128个实例。这样将会提升效率,具体配置如下:

services.AddDbContextPool<DataContext>(options=>{//...},poolSize:256);

Attach

连接现有实体的连接方法现在更聪明了:如果所连接图形中的任何一个实体都有它的键集,它将被标记为unchanged,如果不是,则是new。

Entity Type Configuration

现在我们可以将实体配置存储在不同的类中,就和我们以前拥有的类一样:

publicclassMyEntityTypeConfiguration:IEntityTypeConfiguration<MyEntity>{publicvoidConfigure(EntityTypeBuilder<MyEntity>builder){//...}}

只是这些类不会被自动的发现

modelBuilder.ApplyConfiguration(newMyEntityTypeConfiguration());

全局过滤器(Global Filters)

全局过滤器在pre-Core EF中就已经存在了,他们在通常使用在以下两种情形:

  • 对于多租户应用程序

  • 软删除

软删除是这样来配置的:

modelBuilder.Entity<Post>().HasQueryFilter(p=>!p.IsDeleted);

多租户是这样的:

modelBuilder.Entity<Blog>().HasQueryFilter(p=>p.TenantId==this.TenantId);

它将对任何作为查询结果(包括渴望负载)或从一到多个集合加载的实体应用过滤,但它不会通过id(一对一或多对一)过滤查询。

您可以显式调用IgnoreQueryFilters 扩展方法禁用任何现有的过滤器:

ctx.Blog.IgnoreQueryFilters().ToList();

禁用客户端赋值(Disabling Client-Side Evaluation)

您可能知道EF Core可以对客户端不知道的方法进行客户端赋值,也就是说,不能将其转换为数据库调用。这是透明的,可能会变成性能问题。如果需要禁用此功能,现在可以通过配置日志基础结构在客户端赋值发生时抛出异常:

varbuilder=newDbContextOptionsBuilder<DataContext>().ConfigureWarnings(options=>{options.Throw(RelationalEventId.QueryClientEvaluationWarning);options.Default(WarningBehavior.Log);});

Like

现在我们支持SQL的like函数了,虽然在过去我们也支持类似的东西,通过String.Contains的方法。

就好像这样:

ctx.Posts.Where(x=>EF.Functions.Like(x.Title,“%NET%”).ToList();

不幸的是,微软没有把Like做成一个扩展方法,我认为它更好用。

调用标量函数(Calling Scalar Functions)

调用标量函数也回来了,有一些小的注意事项:

这些功能需要在类中声明静态语境

他们只能返回标量值作为参数

举个例子,首先声明,使用T-SQL的内置函数,通过[ DbFunction]属性:

[DbFunction]publicstaticstringSoundex(stringname){thrownewNotImplementedException();}

或者

modelBuilder.HasDbFunction(this.GetType().GetMethod(“Soundex”));

无论哪种情况,您都可以指定模式或函数的名称,如果它与所使用的方法不同:

[DbFunction("FuncName",Schema="dbo")]modelBuilder.HasDbFunction(this.GetType().GetMethod("FuncName"),options=>{options.HasName("FuncName");options.HasSchema("dbo");});

或者这样用

varsounds=ctx.MyEntity.Select(x=>x.Soundex(x.Name)).ToList();

支持字符串插值(String Interpolation Support)

现在,FromSql和ExecuteSqlCommand方法支持插入字符串了,并且它会产生所需的参数。您不必担心那些由于查询计划创建时而引起的SQL注入攻击和性能问题了。

具体是这样做的:

ctx.Database.ExecuteSqlCommand($"UPDATERecordSETValue={value}WHEREId={id}");

显式编译查询(Explicitly Compiled Queries)

Entity Framework Core包含了version 1以来就有的查询缓存,但仍有一些开销是与从查询中计算密钥并从缓存中获取密钥有关。因此,version 2引入了Entity Framework pre-Core 中就存在的LINQ to SQL能力:显式查询编译和执行。通过这一点,我们能够预先编译一个查询,并在我们想要的任何上下文中使用它(当然是兼容类型的)。我们甚至可以热切取相关的集合或实体:

staticreadonlyFunc<MyEntityContext,int,IEnumerable<MyEntity>>CompiledQuery=EF.CompileQuery<MyEntityContext,int,MyEntity>((ctx,id)=>ctx.MyEntities.Where(x=>x.Id==id).Include(x=>x.Others).OrderBy(x=>x.Name));

如您所见,它返回一个委托,我们可以调用它传递适当的参数——在这个例子中,有一个上下文和一个参数,但是我们可以提到到有8个不同类型的参数:

varresults=CompiledQuery(ctx,100).ToList();

打断变化(Breaking Changes)

IDbContextFacfory<T>接口被IDesignTimeDbContextFactory<T>接口所替代,CreateDbContext这个签名方法当然也被修改了:

publicclassDummyContextFactory:IDesignTimeDbContextFactory<DummyContext>{publicDummyContextCreateDbContext(string[]args){varbuilder=newDbContextOptionsBuilder<DummyContext>();builder.UseSqlServer("…");returnnewDummyContext(builder.Options);}}

UseInMemoryDatabase现在需要一个名字了:

optionsBuilder.UseInMemoryDatabase("MyDatabase")

Microsoft.EntityFrameworkCore.SqlServer.Design过时了,需要改成使用Microsoft.EntityFrameworkCore.Design。

只有2.0 内容的能够工作, 因此,基于EF Core 1.x 的内容基本都需要重写。

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表