2026 年 50 道 Entity Framework 面试题及答案

准备 Entity Framework 面试意味着要预判那些能够考察应聘者真正能力的面试问题。Entity Framework 面试题旨在考察应聘者的思维方式、绩效意识以及将概念转化为实践的能力。
精通 Entity Framework 能让你在整个现代开发领域(从数据驱动平台到云服务)找到合适的职位。实践经验能够提升分析能力、增强技术深度并为团队提供支持。招聘负责人重视实际问题解决能力、可扩展设计能力、指导初级开发人员的能力以及为应届毕业生提供的职业发展路径。 阅读全文...
👉 免费PDF下载:Entity Framework面试题及答案
Entity Framework 面试题及答案
1)什么是 Entity Framework?为什么要使用它?
实体框架(EF)是 Microsoft的 .NET ORM(对象关系映射)框架 它简化了数据库交互,允许开发人员将数据作为强类型 .NET 对象而非原始 SQL 进行操作。这种抽象使开发人员能够使用熟悉的 C# 结构执行 CRUD(创建、读取、更新、删除)操作,而框架会在底层处理将这些操作转换为优化的 SQL 查询。EF 减少了样板数据访问代码,提高了可维护性,并有助于强制执行编译时类型安全。
例如,您可以使用以下方式代替编写 SQL:
var customers = context.Customers.Where(c => c.IsActive).ToList();
EF 会将此 LINQ 查询转换为 SQL,针对数据库执行该查询,并将结果作为对象返回。
2)解释代码优先、数据库优先和模型优先方法之间的区别。
Entity Framework 支持三种主要的开发方法:
| 途径 | 何时使用 | 怎么了 |
|---|---|---|
| 代码优先 | 新项目或领域驱动设计 | 您定义实体类。EF 根据代码生成数据库模式。 |
| 数据库优先 | 现有数据库 | EF 根据现有模式生成实体类和上下文。 |
| 模特第一 | 当您偏爱视觉设计时 | 您可以在可视化设计器(实体设计器)中设计模型,EF 会生成类和数据库。 |
每种方法适用于不同的场景: 代码优先 在敏捷开发中很受欢迎, 数据库优先 更适合用于传统数据库,而且 模特第一 适用于视觉建模至关重要的场景。
3) 什么是 DbContext?它在 EF 中扮演什么角色?
DbContext 是管理的主要类 与数据库的会话它跟踪实体变更,并协调将数据保存回数据库。它充当了 C# 应用程序和数据库之间的桥梁。 DbContext你定义 DbSet<TEntity> 属性代表实体的集合,并映射到数据库中的表。
计费示例:
public class AppDbContext : DbContext
{
public DbSet<Product> Products { get; set; }
}
在这里, Products 充当执行 CRUD 操作的集合。EF 使用此上下文来 跟踪对象状态 并生成 SQL 命令 SaveChanges().
4) Entity Framework 中的迁移是什么?它们是如何使用的?
迁移 是一种跟踪和应用的机制 架构更改 随着时间的推移,数据库会不断更新。随着模型的演进,迁移可以帮助保持数据库同步,而无需手动修改 SQL 脚本。使用 Code First 时,您可以使用如下命令:
Add-Migration InitialCreate Update-Database
此操作会生成定义模式变更的迁移类,并将其应用到数据库。迁移允许对数据库模式进行版本控制,并促进协作开发。
5)描述延迟加载、立即加载和显式加载。
在 EF 中,高效加载相关数据至关重要。以下是对比:
| 策略 | 运行时 | 典型用途 |
|---|---|---|
| 延迟加载 | 首次访问时加载相关数据 | 当并非总是需要相关数据时,可以使用此方法。 |
| 预先加载 | 相关数据预先加载 .Include() |
当您需要相关数据时使用。 |
| 显式加载 | 查询后手动加载 | 可以精确控制相关数据的加载时间。 |
例如:
var orders = context.Orders.Include(o => o.Customer).ToList(); // Eager
延迟加载有助于减少初始查询,但可能会导致 N+1个查询问题 如果不小心使用。
6) Entity Framework 中的变更跟踪是什么?
变更跟踪是 EF 的内部机制。 监控实体状态变化 查询执行后,当检索到实体时 DbContext它会被跟踪。对其属性的任何修改都会被记录下来,并且当 SaveChanges() 调用时,EF 会生成相应的 SQL。 INSERT, UPDATE 或 DELETE 声明。对于不需要跟踪的只读场景, AsNoTracking() 禁用变更跟踪,从而提高性能。
7) Entity Framework 如何处理并发冲突?
并发控制确保多个用户更新同一数据时不会意外覆盖彼此的更改。EF 使用 乐观并发 默认情况下。一种常见的方法是添加一个 并发令牌 (像一个 RowVersion 时间戳)。EF 在期间检查此令牌 SaveChanges()如果它与数据库版本不同,则 DbUpdateConcurrencyException 抛出异常,表示存在冲突。开发人员可以处理此异常以重试或解决数据差异。
8) EF 中的导航属性是什么?
导航属性定义了实体之间的关系。它们允许 EF 执行以下操作: 浏览关联 (例如,一对多关系)无需手动连接:
public class Order
{
public int Id { get; set; }
public Customer Customer { get; set; }
}
在这里, Customer 是一个导航属性链接 Order 与其相关 CustomerEF 使用这些属性在查询期间自动构建关系和连接。导航属性与此协同工作。 外键 建立关系模型。
9) AsNoTracking() 的目的是什么?
AsNoTracking() 禁用查询的更改跟踪,这有利于…… 唯读 执行某些操作时,您无需更新检索到的实体。这可以通过减少内存使用和跟踪开销来提高性能。在获取大型数据集而不对其进行修改时,这种方法尤其有用。
10)什么是编译查询?何时应该使用编译查询?
编译查询是一种性能优化技术。当执行 LINQ 查询时,EF 通常每次都会将其转换为 SQL。而使用编译查询,这种转换只需执行一次,生成的委托即可重用,从而降低频繁执行或复杂查询的开销。 高流量 同一查询使用不同参数重复运行的场景。
11) Entity Framework 中的实体状态是什么?它们如何影响 SaveChanges()?
实体框架跟踪每个实体的 州 确定在数据库操作期间要执行什么操作 SaveChanges()主要实体状态如下:
| 州 | 描述 | Opera触发 |
|---|---|---|
| 增强保护 | 要插入的新实体 | INSERT |
| 修改日期 | 现有实体已更新 | UPDATE |
| 删除 | 实体被标记为移除 | DELETE |
| 不变的 | 未检测到任何变化 | 没有 |
| 分离的 | 未按上下文跟踪 | 没有 |
你打电话时 SaveChanges()EF 会检查实体状态并执行相应的 SQL 命令。例如,向实体表中添加一个新实体。 DbSet 将被标记 增强保护,导致 INSERT 查询。
计费示例:
context.Entry(product).State = EntityState.Modified; context.SaveChanges();
此操作会明确更新实体的数据库记录。
理解状态 确保更好地控制数据同步和性能。
12) 使用 Entity Framework 的优点和缺点是什么?
Entity Framework 提供了强大的优势,但也存在一些不足,具体取决于您的使用场景。
| 性能 | 缺点 |
|---|---|
| 通过 LINQ 和对象模型简化数据访问。 | 与原始 ADO.NET 相比,性能开销较大。 |
| 减少重复的SQL代码。 | 复杂的查询可能会生成效率低下的 SQL。 |
| 支持多种数据库提供商。 | 生成的SQL语句更难调试。 |
| 强类型,提高了编译时安全性。 | 大型团队中可能出现迁移冲突。 |
| 支持使用代码优先进行快速原型设计。 | Less 对微调查询的控制。 |
对于需要最高性能的大型系统,开发人员仍然可以混合使用这两种方法。 使用 EF 的原始 SQL 进行优化。
13) Entity Framework 如何处理关系(一对一、一对多、多对多)?
实体框架通过以下方式管理关系 导航属性 以及 外国关键关联.
人际关系的类型有:
| 关系类型 | 描述 | 例如: |
|---|---|---|
| 一到一 | 每个实体实例都有一个关联实体。 | User ↔ UserProfile |
| 一对多 | 一个实体与多个其他实体相关联。 | Customer → Orders |
| 多对多 | 多个实体之间存在关联。 | Student ↔ Course |
一个例子 一对多 关系:
public class Customer
{
public int CustomerId { get; set; }
public ICollection<Order> Orders { get; set; }
}
EF 会自动生成外键和句柄 级联删除规则 取决于配置。
您还可以使用 流利的API 为了更明确地建立关系。
14) LINQ to Entities 和 LINQ to SQL 有什么区别?
| 专栏 | LINQ 到实体 | LINQ 到 SQL |
|---|---|---|
| 支持的数据库 | 多个(SQL Server, Oracle, MySQL等) | 仅限 SQL Server |
| 底层框架 | 实体框架 | ADO.NET |
| 型号 | 概念实体模型 | 仅数据库表 |
| 地图绘制 | 复杂映射(遗传、关联) | 直接表映射 |
| 未来的支持 | 积极支持 | 已过时 |
LINQ 到实体 是 Entity Framework 的一部分,而且功能更强大; LINQ 到 SQL 仅限于 SQL Server 和较简单的用例。
因此,建议在企业级开发中使用 LINQ to Entities。
15)ObjectContext 和 DbContext 有什么区别?
| 专栏 | ObjectContext | 数据库上下文 |
|---|---|---|
| 骨架 | 早期的 EF 版本 | EF 4.1+ 中的简化 API |
| 复杂 | 更详细 | 轻巧便捷 |
| 性能 | 速度稍快,但使用起来更难。 | 简化设计,开销极小 |
| 变更追踪 | 需要手动配置 | 自动追踪 |
| 首选用途 | 遗留系统 | 现代 EF / EF Core 项目 |
DbContext 内部包裹 ObjectContext 但它提供了更简洁、更直观的 API。大多数当前的 .NET 应用程序都应该使用 DbContext.
16) 解释实体框架中实体的生命周期。
实体的生命周期描述了它的 状态转换 从创造到延续:
- 创建 – 实体在内存中实例化(状态: 分离的).
- 附件 – 通过以下方式添加到上下文中
DbSet.Add()(状态: 增强保护). - 修改 – 自动检测到更改(状态: 修改日期).
- 坚持 –
SaveChanges()调用 → 执行 SQL 命令。 - 缺失 – 标记为 删除 并从数据库中删除。
了解此生命周期有助于调试数据问题和优化 EF 上下文管理。
17) Entity Framework 中 Fluent API 的用途是什么?
此 流利的API 提供了一种以编程方式配置模型关系、约束和映射的方法,通常用于: OnModelCreating() 你的方法 DbContext.
它能够对配置进行精细控制, 数据注释 无法表达。
计费示例:
modelBuilder.Entity<Customer>()
.HasMany(c => c.Orders)
.WithOne(o => o.Customer)
.HasForeignKey(o => o.CustomerId);
Fluent API 在配置方面尤其强大 复合密钥, 多对多关系和 级联规则.
18) Entity Framework 中的数据注解是什么?
数据标注是 属性 直接应用于模型类或属性以定义模式行为。它们比 Fluent API 更简单,但灵活性较差。
计费示例:
public class Product
{
[Key]
public int ProductId { get; set; }
[Required]
[StringLength(50)]
public string Name { get; set; }
}
注解定义了键、字符串长度、必填字段和关系。对于高级情况,开发人员通常会结合使用注解。 数据注释 以及 流利的API.
19) EF Core 中的跟踪实体和非跟踪实体之间有什么区别?
| 类型 | 描述 | 用例 |
|---|---|---|
| 跟踪实体 | 由……监控 DbContext 进行更改。 |
更新的默认行为。 |
| 未跟踪实体 | 未监控;检索方式 .AsNoTracking(). |
非常适合只读操作。 |
跟踪的实体会消耗更多内存,但可以让 EF 自动检测更改。
未跟踪的实体增强 性能 在高阅读量、低更新量的情况下。
20) 如何在 Entity Framework 中执行原始 SQL 查询?
Entity Framework 允许执行原始 SQL,以进行自定义查询或对性能要求极高的查询。
var result = context.Products
.FromSqlRaw("SELECT * FROM Products WHERE Price > 100")
.ToList();
对于非查询命令:
context.Database.ExecuteSqlRaw("DELETE FROM Products WHERE Discontinued = 1");
谨慎使用此功能,以免 SQL注入 并保持与数据库无关的灵活性。
21) Entity Framework 和 Entity Framework Core 有什么区别?
Entity Framework (EF) 和 Entity Framework Core (EF Core) 在架构、功能和跨平台支持方面有所不同。
| 专栏 | 实体框架 6 (EF6) | 实体框架核心 |
|---|---|---|
| 平台 | 仅限 .NET Framework | 跨平台(.NET 5/6/7) |
| 卓越 | 基于对象上下文 | 轻巧且模块化 |
| 性能 | 某些查询速度较慢 | 优化查询生成 |
| LINQ 支持 | 成熟但有局限性 | 改进的翻译和异步 |
| 数据库提供商 | SQL 服务器, Oracle | 多种的 (MySQL, PostgreSQL, SQLite等) |
| 产品特性 | 成熟的(例如,延迟加载) | 现代(例如,阴影属性、全局过滤器) |
EF Core 是 现代的、积极发展的 由于其灵活性和性能,该版本是新建 .NET 项目的推荐选择。
22) Entity Framework 中的事务是如何工作的?
实体框架中的事务确保 数据的完整性 当多个操作必须同时成功或失败时。默认情况下,EF 会进行包装。 SaveChanges() 在交易内部。用于手动控制:
using (var transaction = context.Database.BeginTransaction())
{
try
{
context.Customers.Add(new Customer());
context.SaveChanges();
context.Orders.Add(new Order());
context.SaveChanges();
transaction.Commit();
}
catch
{
transaction.Rollback();
}
}
这样可以确保原子性——如果任何命令失败,所有更改都会回滚。
EF 还与 系统.事务 支持分布式事务。
23) 解释 Entity Framework 中的 TPH、TPT 和 TPC 继承策略。
Entity Framework 支持三种主要的继承映射策略来建模类层次结构。
| 策略 | 描述 | 例如: | 性能 | 缺点 |
|---|---|---|---|---|
| TPH(每层级表格数) | 所有类别共用一个表;鉴别器列用于标识类型。 | EF Core 中常见。 | 简单快捷的查询。 | 表格可能会变得很大但内容稀疏。 |
| TPT(按类型划分的表格) | 每个子类都有自己的表格。 | 每个派生类都单独映射。 | 规范化模式。 | 大型层级结构上的连接速度较慢。 |
| TPC(混凝土等级表) | 每个类别都有自己的表格,并且表格中存在重复的列。 | 每个实体单独映射。 | 高效读取。 | 数据冗余。 |
大多数开发者更喜欢 TPH 为了简单起见,除非出于规范化或性能方面的需要另有规定。
24) 如何在 Entity Framework 中进行性能调优?
为了优化 Entity Framework 的性能:
- 使用 VHDL 语言编写
AsNoTracking()用于只读查询。 - 渴望的负荷 仅与必要的关联实体
.Include(). - 避免 N+1 查询 使用投影或
Select(). - 使用编译后的查询 用于频繁运行的操作。
- 批量插入/更新 -
AddRange()以及SaveChanges(). - 禁用自动检测更改 用于批量操作:
context.Configuration.AutoDetectChangesEnabled = false; - 使用缓存和分页 适用于大型数据集。
经过精心调校的 EF 实现可以达到 ADO.NET 的性能,同时保持开发人员的生产力。
25) Entity Framework Core 中的影子属性是什么?
A 阴影属性 它存在于 EF 模型中,但不存在于实体类中。它由 EF 在变更跟踪器中维护,并存储在数据库中。
计费示例:
modelBuilder.Entity<Order>()
.Property<DateTime>("LastUpdated");
这样,EF 就可以存储额外的元数据(例如时间戳、审计信息),而无需修改实体类。
您可以通过以下方式访问影子属性:
var value = context.Entry(order).Property("LastUpdated").CurrentValue;
影子属性非常适合用于日志记录或审计场景。
26) EF Core 中的值转换器是什么?
EF Core 中的值转换器允许在从数据库读取或写入数据库时转换属性值。
例如,要将枚举值存储为字符串:
modelBuilder.Entity<Employee>()
.Property(e => e.Status)
.HasConversion(
v => v.ToString(),
v => (EmployeeStatus)Enum.Parse(typeof(EmployeeStatus), v));
这增强了自定义数据类型的灵活性,例如 enum, bool 或 DateTimeOffset.
值转换器也用于 加密、压缩或掩码 敏感数据。
27)什么是全局查询过滤器,它们是如何工作的?
全局查询筛选器允许自动将条件应用于针对某个实体的所有查询。
这对于 软删除 or 多租户.
计费示例:
modelBuilder.Entity<Employee>()
.HasQueryFilter(e => !e.IsDeleted);
针对每个查询执行 Employee 除非明确更改,否则会自动排除软删除的记录。
全局过滤器可提高可维护性和数据安全性。
28) 如何使用单元测试来测试 Entity Framework 代码?
要在不访问真实数据库的情况下对 EF 逻辑进行单元测试,请使用 内存数据库 or 嘲讽:
- 选项 1:内存提供程序
var options = new DbContextOptionsBuilder<AppDbContext>() .UseInMemoryDatabase("TestDb") .Options; - 选项 2:模拟 DbContext
嘲笑DbSet使用诸如此类的库 起订量 用于独立测试。
单元测试应验证:
- 查询正确性(通过 LINQ)
- 数据一致性
SaveChanges() - 存储库逻辑
使用 EF Core InMemory 进行测试可确保速度并避免对 SQL Server 的依赖。
29) 解释 EF 中的存储库和工作单元模式。
这两种建筑模式有助于 抽象数据访问 以及 保持交易一致性.
| 模式 | 目的 | 实施例 |
|---|---|---|
| 存储库 | 封装每个实体的 CRUD 操作。 | IRepository<T> 接口 Add(), GetAll()等等。 |
| 工作单元 | 协调事务中的多个存储库。 | SaveChanges() 充当提交边界。 |
计费示例:
public class UnitOfWork : IUnitOfWork
{
private readonly AppDbContext _context;
public void Commit() => _context.SaveChanges();
}
这些模式有所改善 可测试性, 代码重用和 关注点分离 在大型企业应用中。
30)预加载和投影加载有什么区别?
| 方面 | 预先加载 | 投影载荷 |
|---|---|---|
| 目的 | 预先加载相关数据 | 仅加载特定字段或属性 |
| 付款方式 | .Include() |
.Select() |
| 例如: | context.Orders.Include(o => o.Customer) |
context.Orders.Select(o => new { o.Id, o.Customer.Name }) |
| 性能 | 获取完整对象 | 获取最小数据 |
| 用例 | 当需要相关实体进行处理时 | 当您需要特定的轻量级数据时 |
投影载荷是一种 性能优化 通过仅选择必要的列来减少内存开销。
31) Entity Framework Core 中的拦截器是什么?
EF Core 中的拦截器允许开发人员拦截和修改数据库操作,例如: 查询执行、命令创建和连接打开.
它们充当 EF 和数据库提供商之间的中间件组件。
计费示例: 记录所有已执行的 SQL 命令。
public class CommandInterceptor : DbCommandInterceptor
{
public override void ReaderExecuting(
DbCommand command,
CommandEventData eventData,
InterceptionResult<DbDataReader> result)
{
Console.WriteLine($"Executing SQL: {command.CommandText}");
base.ReaderExecuting(command, eventData, result);
}
}
您需要在……中注册。 DbContextOptionsBuilder:
optionsBuilder.AddInterceptors(new CommandInterceptor());
产品优势
- 增强型日志记录
- 安全性(查询验证)
- 审计和绩效跟踪
32) EF Core 如何处理异步操作?
Entity Framework Core 完全支持 异步编程 通过诸如 SaveChangesAsync(), ToListAsync()和 FirstOrDefaultAsync().
异步执行有助于 提高可扩展性 在 Web 应用程序中,通过释放线程来等待 I/O 密集型数据库操作。
计费示例:
var customers = await context.Customers
.Where(c => c.IsActive)
.ToListAsync();
异步操作在高吞吐量场景下尤其有效。 ASP.NET Core API 以及微服务,减少阻塞调用并提高响应速度。
33) Entity Framework Core 中的连接弹性是什么?
连接稳定性有助于您的应用程序。 自动从瞬态数据库故障中恢复例如网络中断或 SQL 超时。
它可以按如下方式配置:
optionsBuilder.UseSqlServer(
connectionString,
options => options.EnableRetryOnFailure(5, TimeSpan.FromSeconds(10), null)
);
在这里,EF 将对失败的操作进行最多 5 次重试,每次重试之间会有延迟。
这在以下方面尤其有用: 云托管环境 喜欢 Azure SQL 中瞬态故障很常见。
34) EF Core 中的所有权实体类型是什么?
拥有的实体允许建模 值对象 完全取决于另一个实体的生命周期。
它们与它们的主人共用一张桌子,不能独立存在。
计费示例:
public class Address
{
public string Street { get; set; }
public string City { get; set; }
}
public class Customer
{
public int Id { get; set; }
public Address Address { get; set; }
}
配置:
modelBuilder.Entity<Customer>().OwnsOne(c => c.Address);
使用案例:
建模概念如 地址, 金钱 或 多维数据监测 它们没有自己的身份。
35) 如何在 Entity Framework Core 中实现软删除?
软删除是指将记录标记为已删除,而不是实际删除它们。
它们采用以下方式实现: 布尔标志 以及 全局查询过滤器.
modelBuilder.Entity<Employee>()
.HasQueryFilter(e => !e.IsDeleted);
在删除操作中:
employee.IsDeleted = true; context.Update(employee); context.SaveChanges();
优点:
- 历史数据保存
- 更容易恢复
缺点:
- 更大的数据库表
- 需要精心设计的过滤逻辑
36) EF Core 中的编译模型是什么?为什么要使用它?
在 EF Core 6+ 中, 编译模型 允许将 EF 模型元数据预编译成 .NET 程序集,从而减少启动时间和运行时开销。
步骤:
- 运行命令:
dotnet ef dbcontext optimize - EF 生成一个预编译的模型文件,应用程序在运行时可以更快地加载该文件。
受益: 可将初始化延迟降低 30-40%,尤其是在具有大量实体的大型应用程序中。
使用案例: 高性能微服务和无服务器环境。
37) 如何在 Entity Framework 中实现缓存?
缓存有助于减少重复的数据库查询。缓存主要分为两个层次:
| 类型 | 描述 | 例如: |
|---|---|---|
| 一级缓存 | 内置,每 DbContext 例 |
自动管理 |
| 二级缓存 | 跨上下文共享的外部缓存 | 使用类似的库 EFCoreSecondLevelCacheInterceptor |
二级缓存示例:
services.AddEFSecondLevelCache(options =>
{
options.UseMemoryCacheProvider().DisableLogging(false);
});
这显著提高了性能 读取密集型应用 通过避免冗余的数据库查询。
38) EF Core 如何管理并发令牌和时间戳?
并发令牌可防止 相互冲突的更新 在多用户环境下。
您可以使用以下方法将属性标记为并发令牌: [ConcurrencyCheck] or [Timestamp] 属性。
计费示例:
public class Product
{
public int Id { get; set; }
[Timestamp]
public byte[] RowVersion { get; set; }
}
当发生更新时,EF 会将此列包含在内。 WHERE 条款。
如果值不匹配,则 DbUpdateConcurrencyException 被抛掷——确保 乐观并发控制.
39) 如何在 EF Core 中实现审计(创建、修改、删除跟踪)?
审核跟踪元数据,例如 谁创建、修改或删除了 纪录。
你可以覆盖 SaveChanges():
public override int SaveChanges()
{
var entries = ChangeTracker.Entries()
.Where(e => e.Entity is IAuditable &&
(e.State == EntityState.Added || e.State == EntityState.Modified));
foreach (var entry in entries)
{
var auditable = (IAuditable)entry.Entity;
auditable.LastModified = DateTime.UtcNow;
}
return base.SaveChanges();
}
接口:
public interface IAuditable
{
DateTime Created { get; set; }
DateTime LastModified { get; set; }
}
这种方法集中了审计逻辑,确保 一致的数据治理.
40)在企业应用程序中使用 Entity Framework 的最佳实践是什么?
| 类别 | 最佳实践 | 好处 |
|---|---|---|
| 性能 | 使用 VHDL 语言编写 AsNoTracking() 以及只读查询的预测。 |
降低运营成本。 |
| 工艺设计 | 实现存储库模式和工作单元模式。 | 提高可维护性。 |
| 安保防护 | 使用参数化查询可以避免 SQL 注入。 | 数据保护。 |
| 可扩展性 | 使用连接池和异步方法。 | 可承受高负载。 |
| 迁移 | 使用版本控制进行自动化迁移。 | 简化模式管理。 |
| 配置 | 将连接字符串和密钥外部化。 | 更好的环境隔离。 |
| 测试与验证 | 单元测试请使用内存提供程序。 | 测试运行速度更快。 |
| 记录 | 启用 EF 日志记录以获取性能分析。 | 更容易调试。 |
这些做法确保 稳健、可扩展且易于维护 基于 Entity Framework 构建的应用程序。
41) 如何在 Entity Framework 中优化 LINQ 查询以获得更好的 SQL 转换?
Entity Framework 会自动将 LINQ 查询转换为 SQL,但低效的模式会导致 SQL 查询速度慢或冗余。优化 LINQ 可以确保 ORM 生成高性能的数据库查询。
优化技术:
使用投影:
- 仅选择所需的列,而不是整个实体。
- 避免客户端评估:
务必确保过滤过程进行。 在 SQL 中不在内存中。当评估在客户端进行时,EF Core 会发出警告。 - 使用 VHDL 语言编写
AsNoTracking()用于只读数据。 - 利用已编译的查询 用于重复的 LINQ 操作。
- 避免不必要
.Include()电话 — 仅在需要时才包含相关数据。
var customers = context.Customers
.Select(c => new { c.Id, c.Name })
.ToList();
var orders = context.Orders.AsNoTracking().ToList();
计费示例:
效率低下:
context.Customers.ToList().Where(c => c.IsActive);
高效:
context.Customers.Where(c => c.IsActive).ToList();
42) 在 EF Core 中,有哪些不同的方法来播种初始数据?
数据填充确保数据库拥有 默认或参考数据 创建时。
方法一:使用模型构建器
modelBuilder.Entity<Role>().HasData(
new Role { Id = 1, Name = "Admin" },
new Role { Id = 2, Name = "User" }
);
这会在整个过程中自动插入数据。 Update-Database.
方法二:自定义种子方法
启动时手动执行代码:
context.Database.Migrate();
if (!context.Users.Any())
{
context.Users.Add(new User { Name = "Admin" });
context.SaveChanges();
}
方法三:SQL脚本
在迁移中使用原始 SQL:
migrationBuilder.Sql("INSERT INTO Roles (Name) VALUES ('Admin')");
建议:
使用 VHDL 语言编写 HasData() 用于静态参考数据和动态启动数据的程序化种子。
43) EF Core 内部如何管理数据库提供程序?
EF Core 是 与提供商无关这意味着它可以通过单独的接口来针对多个数据库引擎。 数据库提供程序包.
常见提供者:
| Provider | NuGet 小包装 | 数据库 |
|---|---|---|
| SQL服务器 | Microsoft.EntityFrameworkCore.SqlServer |
MSSQL |
| SQLite | Microsoft.EntityFrameworkCore.Sqlite |
移动/桌面 |
| PostgreSQL | Npgsql.EntityFrameworkCore.PostgreSQL |
PostgreSQL |
| MySQL | Pomelo.EntityFrameworkCore.MySql |
MySQL |
| 宇宙数据库 | Microsoft.EntityFrameworkCore.Cosmos |
NoSQL的 |
内部,EF Core 使用 抽象层 为:
- 查询翻译
- SQL 命令生成
- 数据类型映射
每个提供程序都实现了自己的类,这些类继承自 EF Core 的基本抽象(例如, RelationalDatabaseProvider, QuerySqlGenerator).
44)什么是“拆分查询”,何时应该使用它?
拆分查询会阻止 EF 执行操作 大型复杂连接 通过执行多个 SQL 查询而不是一个。
计费示例:
var customers = context.Customers
.Include(c => c.Orders)
.AsSplitQuery()
.ToList();
执行此操作:
- 查询 1 → 获取客户
- 查询 2 → 获取与这些客户相关的订单
产品优势
- 防止出现较大的笛卡尔积。
- 提高了处理大型相关数据集的性能。
退税:
多次往返数据库。
使用 VHDL 语言编写 拆分查询 预加载大量相关数据时可能会导致内存问题。
45) 如何有效地监控 EF 生成的 SQL 命令?
监控 SQL 有助于调试缓慢的查询并优化 ORM 行为。
记录 SQL 的方法:
- 控制台日志记录
- ILoggerFactory 集成
- 拦截器 实施
DbCommandInterceptor捕获命令和时间信息。 - 分析工具 使用以下工具:
- 小型探查器
- SQL Server 探查器
- EFCorePowerTools
optionsBuilder
.UseSqlServer(conn)
.LogTo(Console.WriteLine, LogLevel.Information);
var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole()); optionsBuilder.UseLoggerFactory(loggerFactory);
日志记录应该 选择性启用 在生产环境中避免性能开销。
46) ChangeTracker.DetectChanges() 和 AutoDetectChangesEnabled 有什么区别?
| 专栏 | DetectChanges() |
AutoDetectChangesEnabled |
|---|---|---|
| 类型 | 付款方式 | 特性 |
| 目的 | 强制 EF 扫描跟踪的实体并检测变化 | 启用/禁用自动变更检测 |
| 默认 | 用户手册 | 真 |
| 用法 | 明确要求进行性能优化 | 禁用批量更新 |
计费示例:
context.ChangeTracker.AutoDetectChangesEnabled = false;
foreach (var item in list)
{
context.Add(item);
}
context.SaveChanges();
禁用循环中的自动检测功能,性能最多可提升 40% 批量操作。
47) 如何在 EF Core 中使用时间表?
时态表(SQL Server 2016 中引入)允许您: 跟踪历史数据 自动。
步骤:
- 启用迁移中的临时支持:
- 查询历史数据:
builder.Entity<Employee>()
.ToTable("Employees", b => b.IsTemporal());
var history = context.Employees
.TemporalAsOf(DateTime.UtcNow.AddDays(-7))
.ToList();
优点:
- 内置数据历史记录跟踪
- 审计与合规
- 无需手动触发
EF Core 6+ 支持完整的时态查询。
48) EF Core 如何同时支持编译查询和预生成模型?
编译查询和编译模型是两个方面。 性能特点 相互补充。
| 专栏 | 目的 |
|---|---|
| 已编译查询 | 缓存查询翻译结果 |
| 编译模型 | 预编译模型元数据 |
编译后的查询示例:
static readonly Func<AppDbContext, int, Customer> _getCustomerById =
EF.CompileQuery((AppDbContext ctx, int id) =>
ctx.Customers.FirstOrDefault(c => c.Id == id));
用法:
var customer = _getCustomerById(context, 5);
一起: 编译模型减少 启动成本而编译后的查询则减少 运行时查询开销 — 非常适合 高频查询.
49)在微服务架构中使用 EF 时常见的陷阱有哪些?
常见错误:
- 跨服务共享 DbContext
→ 违反了微服务隔离原则。
→ 每个微服务都应该有自己的 DbContext 和 schema。 - 闲聊式沟通(N+1 查询)
→ 尽量减少每次 API 调用中的 EF 查询次数。 - 过分急切地加载
→ 仅通过 DTO 加载所需内容。 - 集中式迁移
→ 每个服务都应该独立管理自己的迁移。 - 缺乏交易边界
→ 如果需要跨服务的一致性,请使用分布式事务(出站箱模式)。 - 与 SQL 提供程序紧密耦合
→ 使用存储库抽象来保持数据库选择的灵活性。
50) 在 ASP.NET Core 中,依赖注入如何与 DbContext 集成?
Entity Framework 与 ASP.NET Core 内置的依赖注入 (DI) 系统。
建立:
services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("Default")));
然后将其注入到控制器或服务中:
public class CustomerService
{
private readonly AppDbContext _context;
public CustomerService(AppDbContext context)
{
_context = context;
}
}
生命周期:
| 终身版 | 描述 | 推荐使用 |
|---|---|---|
| 范围 | 每个 HTTP 请求一个上下文 | 默认 |
| 瞬 态 | 每次都是新的实例 | 背景工作 |
| 独生子 | 全球共享 | 避免(非线程安全) |
使用依赖注入可确保 可测试性、生命周期管理和 资源效率 跨网页和后台进程。
🔍 Entity Framework 面试题精选,附真实案例及策略性解答
1) 什么是 Entity Framework,为什么它在企业应用程序中使用?
对候选人的期望: 面试官想评估你对 Entity Framework 的基础理解及其在实际应用中的价值。
示例答案: Entity Framework 是一个用于 .NET 的对象关系映射 (ORM) 框架,它允许开发人员使用 .NET 对象而非原始 SQL 来操作数据库。它常用于企业应用程序中,以提高开发效率、减少样板数据访问代码并保持高度的关注点分离。
2)你能解释一下代码优先、数据库优先和模型优先这三种方法之间的区别吗?
对候选人的期望: 面试官想评估你对不同开发工作流程的了解程度,以及何时应该使用哪种工作流程。
示例答案: Code First 从领域类入手,并根据代码生成数据库。Database First 从现有数据库入手,并生成实体类。Model First 使用可视化设计器定义模型,然后同时创建代码和数据库。每种方法的选择都取决于项目需求和现有基础架构。
3) Entity Framework 如何处理表之间的关系?
对候选人的期望: 面试官正在考察你对数据建模和关系映射的理解。
示例答案: Entity Framework 使用导航属性和外键来处理关系。它支持一对一、一对多和多对多关系,允许开发人员使用对象引用而不是连接来遍历相关数据。
4) 请描述一个您使用 Entity Framework 提高数据库性能的情况。
对候选人的期望: 面试官想听一个能体现优化技能的实际例子。
示例答案: 在我之前的职位上,我通过减少不必要的预加载和使用 SELECT 语句实现投影查询来提升性能。这最大限度地减少了从数据库中检索的数据量,并显著缩短了查询执行时间。
5) 在 Entity Framework 中如何管理迁移?
对候选人的期望: 面试官正在评估您在模式变更和版本控制方面的经验。
示例答案: 迁移工作通过内置的迁移工具进行管理,这些工具可以跟踪模型随时间的变化。在之前的职位上,我经常生成并审核迁移脚本,然后再应用它们,以确保数据库在不同环境中的完整性。
6)什么是延迟加载?什么时候应该避免使用它?
对候选人的期望: 面试官想考察你对数据加载策略和性能权衡的理解。
示例答案: 延迟加载会在访问数据时自动加载相关数据。我建议避免在对性能要求极高的场景或 API 中使用它,因为它可能会导致多次意外的数据库调用,从而引发 N+1 查询问题。
7) 在 Entity Framework 中如何处理事务?
对候选人的期望: 面试官正在评估你对数据一致性和错误处理的知识。
示例答案: Entity Framework 通过 DbContext 和 TransactionScope 支持事务。在我之前的工作中,我使用显式事务来确保多个相关的数据库操作要么同时成功完成,要么在失败时回滚。
8) 解释如何在 Entity Framework 中使用依赖注入。
对候选人的期望: 面试官想了解你对现代应用程序架构的理解程度。
示例答案: 依赖注入用于将 DbContext 注入到服务或控制器中。这允许在不更改业务逻辑的情况下模拟或替换上下文,从而提高了可测试性和可维护性。
9) 描述一下您在使用 Entity Framework 时遇到的一个具有挑战性的错误,以及您是如何解决它的。
对候选人的期望: 面试官想考察应聘者的解决问题能力和调试技能。
示例答案: 在我上一份工作中,我遇到了更新分离实体时跟踪冲突的问题。我通过显式设置实体状态并确保上下文只跟踪每个实体的一个实例解决了这个问题。
10) 如何判断 Entity Framework 是否不合适?
对候选人的期望: 面试官想了解你的判断力和选择合适技术的能力。
示例答案: 当应用程序需要极高的数据访问性能或复杂的存储过程逻辑时,我会考虑其他方案。在这种情况下,使用微型 ORM 或原生 ADO.NET 可以提供更高的控制力和效率。
