首先,一些常见的技巧
急切的加载:要与父母同时加载相关数据,请使用Include方法。
var blogs = context.Blogs
.Include(blog => blog.Posts)
.ToList();
影子属性:阴影属性是在实体类中未定义但在EF核心模型中定义的属性。
modelBuilder.Entity<Blog>()
.Property<DateTime>("LastUpdated");
并发控制:当多个用户更新同一记录时处理冲突很重要。您可以使用[ConcurrencyCheck]数据注释属性。
public class Blog
{
public int BlogId { get; set; }
[ConcurrencyCheck]
public string Url { get; set; }
}
数据库播种。您可以在EF Core中播种到数据库
modelBuilder.Entity<Blog>()
.HasData(new Blog {BlogId = 1, Url = "http://sample.com"});
禁用自动检测更改:为了更好地性能,请考虑在不需要的情况下关闭自动电视机行为。
context.ChangeTracker.AutoDetectChangesEnabled = false;
var products = context.Products.AsNoTracking().ToList();
流媒体而不是缓冲:流传输允许您在数据库中读取数据时处理数据,而不是首先在内存中对其进行缓冲。这可以帮助减少记忆使用并提高性能。
using var context = new MyDbContext();
using var stream = context.Blogs.AsNoTracking().Select(b => b.Url)
.AsStream();
await stream.CopyToAsync(Response.Body);
编译的查询:编译的查询可以通过缓存查询执行计划来帮助提高性能。
private static readonly Func<MyDbContext, int, Blog> _blogById =
EF.CompileQuery((MyDbContext context, int id) =>
context.Blogs.FirstOrDefault(b => b.Id == id));
var blog = _blogById(context, 1);
inmemory数据库用于测试的提供商:inmemory数据库提供商允许您创建一个内存数据库以进行测试。它提供了一种轻巧,快速测试您的代码的方法,而无需真正的数据库。这是使用内存提供商的一个示例:
services.AddDbContext<MyDbContext>(options =>
options.UseInMemoryDatabase("TestDatabase"));
数据库视图:数据库视图可以提供您数据的简化和优化表示。
modelBuilder.Entity<Blog>()
.ToView("View_Blogs")
.HasNoKey();
查询过滤器:查询过滤器允许您将全局过滤器应用于查询,这对于实现软删除或多租户方案很有用。这是使用查询过滤器的示例:
modelBuilder.Entity<Blog>()
.HasQueryFilter(b => !b.IsDeleted);
dbContext池池可以通过在请求中重复使用相同的上下文实例来提高Web应用程序的性能。这减少了创建和处置DBContext实例的开销。要在ASP.NET Core应用程序中启用DBContext池,请在启动类中配置服务时使用AddDbContextPool方法:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContextPool<MyDbContext>(options =>
{
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")
);
});
}
assplitquery 方法可以在包括多个导航属性时避免笛卡尔爆炸问题。此方法配置EF核心通过单独的数据库查询加载查询结果中的集合:
var customersWithOrdersAndProducts = context.Customers
.Include(c => c.Orders)
.ThenInclude(o => o.Products)
.AsSplitQuery()
.ToList();
现在让我们深入研究EF Core 7特定功能
插入一排
var blog = new Blog { Name = "MyBlog" };
ctx.Blogs.Add(blog);
await ctx.SaveChangesAsync();
在EF Core 6.0中,此代码将启动事务,执行命令,然后提交事务。在EF Core 7.0中,该交易被删除,从而在Localhost上的性能提高了25%,并且在远程服务器上提高了45%。
插入多行
for (var i = 0; i < 4; i++)
{
var blog = new Blog { Name = "Foo" + i };
ctx.Blogs.Add(blog);
}
await ctx.SaveChangesAsync();
在EF Core 6.0中,这将使用合并语句插入四行,这比四个单独的插入语句要快得多。在EF Core 7.0中,删除了交易,并且还删除了临时表,从而在远程服务器上的性能提高了61%,而Localhost的提高了74%。
。使用 hilo 整数密钥的功能:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>().Property(b => b.Id).UseHiLo();
}
一旦启用了Hilo,SaveChanges输出就会有效,并且类似于GUID方案。
SQL Server临时表。 EF Core 7.0现在支持SQL Server时间表。这使您可以在数据库中直接保留数据更改的历史
modelBuilder.Entity<YourEntity>()
.UseTemporalTable();
编译模型。 EF Core 7.0引入了编译的模型,可以显着提高启动性能。您可以使用它:
var options = new DbContextOptionsBuilder<YourContext>()
.UseModel(YourCompiledModel.Instance)
.Options;
table per-type(tpt)映射。 EF Core 7.0引入了对台式(TPT)映射的支持。
modelBuilder.Entity<YourBaseEntity>()
.ToTable("YourBaseTable");
modelBuilder.Entity<YourDerivedEntity>()
.ToTable("YourDerivedTable");
sqlite在线模式迁移。 EF Core 7.0引入了对SQLite在线模式迁移的支持。
var options = new DbContextOptionsBuilder<YourContext>()
.UseSqlite("YourConnectionString", b =>
b.MigrationsAssembly("YourAssembly"))
.Options;
executeUpdate 和 executedElete 方法。 EF Core 7介绍了两种新方法,即ExecuteUpdate和executedElete,它们执行了记录的更改和删除,而无需加载内存中的实体,从而导致性能提高。但是,必须明确指定更改,因为它们未由EF Core自动检测到。
await db.Posts
.Where(p => p.Id == "3fa85f64-5717-4562-b3fc-2c963f66afa6")
.ExecuteUpdateAsync(s => s
.SetProperty(b => b.AuthorName, "John Smith")
.SetProperty(b => b.Title, b => "EF7 is here!")
.SetProperty(b => b.Text, b => "\t")
.SetProperty(b =>
b.LastUpdateDate, "2022-30-11 17:29:46.5028235"));
await db.Posts
.Where(p => p.Id == "3fa85f64-5717-4562-b3fc-2c963f66afa6")
.ExecuteDeleteAsync();
JSON列。 EF7对JSON列具有本机支持,该列允许将.NET类型映射到JSON文档。这包括可以在聚合中使用的LINQ查询,并将转换为JSON的适当查询构建体。也可以更新并保存更改为JSON文档。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Author>().OwnsOne(
author => author.Contact, ownedNavigationBuilder =>
{
ownedNavigationBuilder.ToJson();
ownedNavigationBuilder
.OwnsOne(contactDetails => contactDetails.Address);
});
}
var authorsByCity = await db.Authors.Where(author => author
.Contact.Address.City == city).ToListAsync();
var authorExists = await db.Authors
.Where(author => author.Id == id)
.FirstOrDefaultAsync();
authorExists.Contact.Address.Street = "1523 Stellar Dr";
await db.SaveChangesAsync();
新查询选项。 EF7为Groupby等查询带来了新功能。下面的示例显示了如何使用Groupby扩展方法完成分组:
var groupByAuthor = db.Posts.GroupBy(p => p.AuthorName).ToList();
批量更新和删除。 EF Core 7介绍了执行批量更新和删除的能力。这使您可以表达类似于LINQ查询的内容,以将更改直接推向数据库。新的ExecutedElete和ExecuteUpdate方法以与要应用LINQ执行方法相同的方式附加到LINQ查询。
context.People
.Where(p => p.PersonId == 1)
.ExecuteDelete();
context.People
.Where(p => p.LastName == "Lehrman")
.ExecuteUpdate(s => s.SetProperty(c => c.LastName, c => "Lerman"));
映射存储过程。 EF Core 7介绍了将存储过程映射到实体的能力。这使您可以使用存储过程在调用Savechanges时执行数据库操作。新的插入程序,更新stordorderprocedure和DeleteSorderStorderProcedure方法允许您将存储的过程映射到实体。
modelBuilder.Entity<Person>()
.InsertUsingStoredProcedure("PeopleInsert",
spbuilder => spbuilder
.HasParameter(p => p.PersonId, pb => pb.IsOutput()
.HasName("id"))
.HasParameter(p => p.FirstName)
.HasParameter(p => p.LastName)
);