Entity Framework Core(EF Core)是一个轻量级、跨平台的对象关系映射(ORM)框架,用于在.NET应用程序中处理数据库操作。它提供了一种将数据库中的数据映射到.NET对象模型的方法,使开发人员可以使用面向对象的方式进行数据库操作,而无需直接编写SQL语句。
上一篇文章讲了如何在C#中构建EF Core模型:C#使用Entity Framework Core处理数据库(一)
1.查询EF Core模型
在上一篇文章中我们编辑了一个名为"Product"的实体,它具有"id"、"Name"和"Price"属性
csharp
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
现在编写一些简单的LINQ查询代码用于从数据库中检索所有产品的名称和价格
csharp
using (var context = new YourEfCoreContext())
{
var products = context.Products
.Select(p => new { p.Name, p.Price })
.ToList();
}
过滤结构中返回的实体
"Filtered include"是Entity Framework Core中的一种技术,允许您在加载相关实体时应用过滤条件。这使您能够对关联实体进行过滤,并仅加载符合特定条件的相关数据,而不是加载全部数据。
在EF Core中,通过使用Where和Include方法结合来实现filtered include。这样可以在检索相关实体时应用筛选条件,以减少检索到的数据量并且只获取符合条件的相关数据。
如果您想要在LINQ查询中进行过滤,并包含特定的实体,您可以使用Where来过滤结果,然后使用Include来包含另一个实体。以下是一个示例代码:
csharp
using (var context = new YourEfCoreContext())
{
var productsWithCategory = context.Products
.Where(p => p.Price > 50) // 过滤价格大于50的产品
.Include(p => p.Category) // 包含关联的Category实体
.ToList();
}
获取生成的SQL
EF Core5.0提供了一种简单快捷的方法来查看生成的SQL
还是上面的例子:
csharp
using (var context = new YourEfCoreContext())
{
var query = context.Products
.Where(p => p.Price > 50)
.Include(p => p.Category);
var sql = query.ToQueryString();
Console.WriteLine(sql);
}
生成的 SQL 查询语句将是以下内容:
SELECT "p"."Id", "p"."Name", "p"."Price", "p"."CategoryId", "c"."Id", "c"."Name"FROM "Products" AS "p" LEFT JOIN "Categories" AS "c" ON "p"."CategoryId" = "c"."Id" WHERE "p"."Price" > 50
定义全局过滤器
在 Entity Framework Core 中,您可以使用全局查询过滤器来自动应用于所有对数据库上下文执行的查询。这在需要对数据进行软删除或者多租户隔离的情况下特别有用。
csharp
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// 添加全局过滤器
modelBuilder.Entity<Product>().HasQueryFilter(p => !p.IsDeleted);
}
2.使用EF Core加载模式
立刻加载实体
在 Entity Framework Core 中,可以使用 Include 或 ThenInclude 方法来立即加载相关实体。立即加载可以避免延迟加载带来的性能问题,确保在查询时将相关实体一起加载到内存中。
csharp
using (var context = new YourEfCoreContext())
{
var product = context.Products
.Include(p => p.Category)
.FirstOrDefault(p => p.Id == productId);
}
在上面的示例中,通过调用 Include(p => p.Category) 方法,我们告诉 EF Core 在检索产品时立即加载与之关联的类别实体。这样,在查询结果返回时,产品及其对应的类别会一并加载到内存中。
请注意,过度使用立即加载可能导致性能问题,因为它会在单个查询中检索大量相关数据。在实际应用中,请根据需要谨慎使用立即加载。
启用延迟加载
在 Entity Framework Core 中,默认情况下是不支持延迟加载的。不过,您可以通过安装 Microsoft.EntityFrameworkCore.Proxies 包并启用 UseLazyLoadingProxies 方法来启用延迟加载功能。以下是一个示例:
- 首先,安装 Microsoft.EntityFrameworkCore.Proxies 包:
bash
Install-Package Microsoft.EntityFrameworkCore.Proxies
- 然后,在创建数据库上下文的地方启用延迟加载:
csharp
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder.UseLazyLoadingProxies();
}
- 启用了延迟加载后,当您访问导航属性时,相关的实体将会在需要时自动从数据库中加载。例如:
csharp
using (var context = new YourEfCoreContext())
{
var product = context.Products.FirstOrDefault(p => p.Id == productId);
// 延迟加载类别实体
var category = product.Category;
}
在这个示例中,当访问 product.Category 时,如果该属性还没有被加载,EF Core 将会立即从数据库中检索相关的类别实体。
请注意,尽管延迟加载提供了便利,但它也可能导致性能问题,并且容易引起 N+1 查询问题。因此,在使用延迟加载时要格外小心。
显示加载实体
另一种加载模式是显示加载,这通常用于在已经获取了一个实体之后,需要加载其相关实体的情况。显式加载允许您在需要时精确控制哪些相关实体被加载,从而避免了不必要的数据加载和性能问题。以下是一个示例:
csharp
using (var context = new YourEfCoreContext())
{
var product = context.Products.FirstOrDefault(p => p.Id == productId);
// 显示加载类别实体
context.Entry(product)
.Reference(p => p.Category)
.Load();
}
在上面的示例中,我们首先获取了一个产品实体,然后使用 context.Entry(product).Reference(p => p.Category).Load() 来显式加载该产品对应的类别实体。这样可以确保在需要时加载相关实体,而不是默认情况下自动加载。
感谢您阅读本文中关于Entity Framework Core的示例代码和说明。希望这些示例能够帮助您更好地理解在C#中Entity Framework Core(EF Core)的查询和加载模式。如果您有任何其他问题或需要进一步的指导,请随时告诉我。祝您编程愉快!