EF和EFCore的区别,性能上有哪些区别,哪个性能高?如何优化EF/EFCore 的性能?

news/2025/1/7 7:35:23/文章来源:https://www.cnblogs.com/chenshibao/p/18653088

Entity Framework (EF) 和 Entity Framework Core (EF Core) 是 Microsoft 提供的两种对象关系映射(ORM)框架,用于在 .NET 应用程序中与关系型数据库进行交互。虽然它们在功能和使用方式上有很多相似之处,但也存在一些重要的区别。以下是 EF 和 EF Core 的详细比较,包括性能上的区别、哪个性能更高以及如何优化它们的性能。

EF 和 EF Core 的主要区别

  1. 平台支持:

    • EF:主要用于 .NET Framework。
    • EF Core:设计为跨平台,支持 .NET Core 及其后续版本,可以运行在 Windows、Linux 和 macOS 上。
  2. 项目结构:

    • EF:包含在 System.Data.Entity 命名空间中。
    • EF Core:包含在 Microsoft.EntityFrameworkCore 命名空间中。
  3. 依赖注入:

    • EF Core:更全面地支持依赖注入(DI),使得配置和管理更加灵活。
    • EF:依赖注入支持相对有限。
  4. 数据库提供程序:

    • EF Core:支持更多的数据库提供程序,包括 SQL Server、SQLite、PostgreSQL、MySQL 等。
    • EF:主要支持 SQL Server 和部分其他数据库。
  5. LINQ 支持:

    • EF Core:支持更多的 LINQ 查询操作,特别是在跨平台和异步操作方面。
    • EF:LINQ 支持相对有限,尤其是在某些复杂的查询方面。
  6. 迁移工具:

    • EF Core:提供了更强大的迁移工具(Migrations)来管理数据库模式的变化。
    • EF:迁移工具相对简单,功能有限。

性能上的区别

  1. 查询性能:

    • EF Core:通常在查询性能上优于 EF,特别是在异步操作和跨平台支持方面。
    • EF:在某些情况下可能性能稍好,特别是在 .NET Framework 的特定优化下。
  2. 内存使用:

    • EF Core:在内存使用方面通常更加高效,特别是在处理大量数据时。
    • EF:在内存使用上可能稍微占用更多资源,特别是在某些复杂的查询和对象图加载情况下。
  3. 启动时间:

    • EF Core:启动时间通常比 EF 更快,特别是在 .NET Core 环境中。
    • EF:在 .NET Framework 环境中启动时间可能稍短。

哪个性能更高?

  • EF Core 在大多数情况下性能优于 EF,特别是在现代 .NET 应用程序中。EF Core 的查询优化、异步支持和跨平台能力使得它在处理大量数据和复杂查询时表现更好。

优化 EF 和 EF Core 的性能

优化 ORM 框架的性能可以显著提高应用程序的整体性能。以下是一些优化 EF 和 EF Core 的方法:

  1. 使用异步操作
  • 异步方法:

    • 使用异步方法(如 ToListAsync、SingleAsync、FirstOrDefaultAsync 等)来减少数据库操作对主线程的阻塞。
  • 示例:

      public async Task<List<User>> GetAllUsersAsync(){return await _context.Users.ToListAsync();}
    
  1. 选择合适的查询模式
  • 明确查询结果:

    • 使用 Select 子句明确指定需要查询的字段,避免加载不必要的数据。
  • 示例:

      public async Task<List<string>> GetAllUserNamesAsync(){return await _context.Users.Select(u => u.Name).ToListAsync();}
    
  1. 延迟加载(Lazy Loading) vs 预加载(Eager Loading)
  • 预加载(Eager Loading):

    • 使用 Include 方法预先加载相关数据,减少后续的数据库访问。

    • 示例

        public async Task<User> GetUserWithOrdersAsync(int userId){return await _context.Users.Include(u => u.Orders).FirstOrDefaultAsync(u => u.UserId == userId);}
      
  • 延迟加载(Lazy Loading):

    • 在访问相关数据时才加载,可以减少初始加载的数据量,但可能导致更多的数据库访问。

    • EF Core 支持延迟加载,但需要额外配置。

    • 示例:

        public class User{public int UserId { get; set; }public string Name { get; set; }public virtual ICollection<Order> Orders { get; set; }}public class Order{public int OrderId { get; set; }public int UserId { get; set; }public virtual User User { get; set; }}// 配置延迟加载protected override void OnModelCreating(ModelBuilder modelBuilder){modelBuilder.Entity<User>().HasMany(u => u.Orders).WithOne(o => o.User).HasForeignKey(o => o.UserId).OnDelete(DeleteBehavior.Cascade);}// 使用延迟加载public async Task<User> GetUserWithOrdersAsync(int userId){var user = await _context.Users.FirstOrDefaultAsync(u => u.UserId == userId);// 延迟加载 Ordersawait _context.Entry(user).Collection(u => u.Orders).LoadAsync();return user;}
      
  1. 使用投影查询(Projection Queries)
  • 投影查询:

    • 使用投影查询将数据直接映射到 DTO(数据传输对象),减少对象的创建和内存使用。
  • 示例:

      public async Task<List<UserDto>> GetAllUsersDtoAsync(){return await _context.Users.Select(u => new UserDto{UserId = u.UserId,Name = u.Name}).ToListAsync();}public class UserDto{public int UserId { get; set; }public string Name { get; set; }}
    
  1. 启用查询缓存
  • 查询缓存:

    • EF Core 通过 FromSqlRaw 或 FromSqlInterpolated 方法支持查询缓存。
    • 自定义查询时可以通过缓存来提高性能。
  • 示例:

      public async Task<List<User>> GetUsersFromRawQueryAsync(){var sql = "SELECT * FROM Users WHERE Active = 1";return await _context.Users.FromSqlRaw(sql).ToListAsync();}
    
  1. 批量操作
  • 批量操作:

    • 使用批量操作(如批量插入、批量更新)来减少数据库操作的数量。
  • 示例:

      public async Task AddUsersAsync(List<User> users){await _context.AddRangeAsync(users);await _context.SaveChangesAsync();}
    
  1. 使用 NoTracking 查询
  • NoTracking 查询:

    • 使用 AsNoTracking 方法进行查询,避免将查询结果附加到上下文,从而减少内存使用和提高查询性能。
  • 示例:

      public async Task<List<User>> GetAllUsersNoTrackingAsync(){return await _context.Users.AsNoTracking().ToListAsync();}
    
  1. 配置连接池
  • 连接池:

    • 确保数据库连接池配置正确,减少连接的开销。
  • 示例:

      services.AddDbContext<ApplicationDbContext>(options =>options.UseSqlServer("YourConnectionString", b => b.EnableRetryOnFailure()));
    
  1. 使用索引
  • 数据库索引:

    • 确保在数据库中为常用查询字段创建索引,提高查询性能。
  • 示例:

    CREATE INDEX idx_user_name ON Users(Name);

  1. 优化数据库查询
  • 使用覆盖索引:

    • 确保查询涉及的所有列都在同一个索引中,以避免全表扫描。
  • 示例:

    CREATE INDEX idx_user_name_age ON Users(Name, Age);

  1. 减少数据库上下文的生命周期
  • 短生命周期:

    • 尽量减少数据库上下文(DbContext)的生命周期,避免长时间持有上下文。
  • 示例

      public class UserService{private readonly Func<ApplicationDbContext> _dbContextFactory;public UserService(Func<ApplicationDbContext> dbContextFactory){_dbContextFactory = dbContextFactory;}public async Task<List<User>> GetAllUsersAsync(){using (var context = _dbContextFactory()){return await context.Users.ToListAsync();}}}
    
  1. 批量更新和删除
  • 批量操作:

    • 使用 ExecuteUpdateAsync 和 ExecuteDeleteAsync 进行批量更新和删除操作。
  • 示例:

      	public async Task UpdateUserEmailAsync(int userId, string newEmail){await _context.Users.Where(u => u.UserId == userId).ExecuteUpdateAsync(setters => setters.SetProperty(u => u.Email, newEmail));}public async Task DeleteUserAsync(int userId){await _context.Users.Where(u => u.UserId == userId).ExecuteDeleteAsync();}
    
  1. 使用 Change Tracker 的功能
  • Change Tracker:

    • 了解和优化 ChangeTracker 的功能,避免不必要的跟踪和更新。
  • 示例:

      public async Task UpdateUserEmailAsync(int userId, string newEmail){var user = new User { UserId = userId, Email = newEmail };_context.Users.Attach(user);_context.Entry(user).Property(u => u.Email).IsModified = true;await _context.SaveChangesAsync();}
    

示例:综合优化
以下是一个综合优化的示例,展示了如何在 EF Core 中应用上述优化策略。

	using Microsoft.EntityFrameworkCore;using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;public class User{public int UserId { get; set; }public string Name { get; set; }public string Email { get; set; }public bool IsActive { get; set; }public virtual ICollection<Order> Orders { get; set; }}public class Order{public int OrderId { get; set; }public int UserId { get; set; }public virtual User User { get; set; }}public class ApplicationDbContext : DbContext{public DbSet<User> Users { get; set; }public DbSet<Order> Orders { get; set; }protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder){optionsBuilder.UseSqlServer("YourConnectionString");}protected override void OnModelCreating(ModelBuilder modelBuilder){modelBuilder.Entity<User>().HasMany(u => u.Orders).WithOne(o => o.User).HasForeignKey(o => o.UserId).OnDelete(DeleteBehavior.Cascade);}}public class UserService{private readonly ApplicationDbContext _context;public UserService(ApplicationDbContext context){_context = context;}public async Task<List<UserDto>> GetAllActiveUsersDtoAsync(){// 使用投影查询和 NoTrackingreturn await _context.Users.Where(u => u.IsActive).Select(u => new UserDto{UserId = u.UserId,Name = u.Name}).AsNoTracking().ToListAsync();}public async Task AddUsersAsync(List<User> users){// 批量添加用户await _context.AddRangeAsync(users);await _context.SaveChangesAsync();}public async Task UpdateUserEmailAsync(int userId, string newEmail){// 使用 AsNoTracking 和 ExecuteUpdateAsyncawait _context.Users.Where(u => u.UserId == userId).ExecuteUpdateAsync(setters => setters.SetProperty(u => u.Email, newEmail));}public async Task DeleteUserAsync(int userId){// 使用 AsNoTracking 和 ExecuteDeleteAsyncawait _context.Users.Where(u => u.UserId == userId).ExecuteDeleteAsync();}public async Task<UserWithOrdersDto> GetUserWithOrdersAsync(int userId){// 预加载 Orders 并使用投影查询var user = await _context.Users.Where(u => u.UserId == userId).Include(u => u.Orders).Select(u => new UserWithOrdersDto{UserId = u.UserId,Name = u.Name,Orders = u.Orders.Select(o => new OrderDto{OrderId = o.OrderId,UserId = o.UserId}).ToList()}).AsNoTracking().FirstOrDefaultAsync();return user;}}public class UserDto{public int UserId { get; set; }public string Name { get; set; }}public class UserWithOrdersDto{public int UserId { get; set; }public string Name { get; set; }public List<OrderDto> Orders { get; set; }}public class OrderDto{public int OrderId { get; set; }public int UserId { get; set; }}public class Program{public static async Task Main(string[] args){var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();optionsBuilder.UseSqlServer("YourConnectionString");using (var context = new ApplicationDbContext(optionsBuilder.Options)){var userService = new UserService(context);// 获取所有活跃用户List<UserDto> activeUsers = await userService.GetAllActiveUsersDtoAsync();Console.WriteLine($"Active Users: {activeUsers.Count}");// 添加用户List<User> newUsers = new List<User>{new User { Name = "Alice", Email = "alice@example.com", IsActive = true },new User { Name = "Bob", Email = "bob@example.com", IsActive = true }};await userService.AddUsersAsync(newUsers);// 更新用户邮箱await userService.UpdateUserEmailAsync(1, "alice_new@example.com");// 删除用户await userService.DeleteUserAsync(2);// 获取用户及其订单UserWithOrdersDto userWithOrders = await userService.GetUserWithOrdersAsync(1);Console.WriteLine($"User: {userWithOrders.Name}, Orders: {userWithOrders.Orders.Count}");}}}

关键点解释

  1. 使用异步操作:
    • ToListAsync、FirstOrDefaultAsync 等异步方法减少阻塞,提高响应性。
  2. 投影查询:
    • Select 子句明确指定需要查询的字段,减少不必要的数据加载。
  3. 预加载(Eager Loading):
    • Include 方法预先加载相关数据,减少后续的数据库访问。
  4. NoTracking 查询:
    • AsNoTracking 方法避免将查询结果附加到上下文,减少内存使用和提高查询性能。
  5. 批量操作:
    • AddRangeAsync 和 SaveChangesAsync 进行批量插入操作。
    • ExecuteUpdateAsync 和 ExecuteDeleteAsync 进行批量更新和删除操作。
  6. 配置连接池:
    • 确保数据库连接池配置正确,减少连接的开销。
  7. 使用索引:
    • 确保在数据库中为常用查询字段创建索引,提高查询性能。

总结

  1. EF 和 EF Core 的区别:
    • EF:主要用于 .NET Framework,依赖注入支持有限。
    • EF Core:支持跨平台,依赖注入支持全面,支持更多的数据库提供程序。
  2. 性能比较:
    • EF Core 在大多数情况下性能优于 EF,特别是在异步操作、跨平台支持和内存使用方面。
  3. 优化策略:
    • 使用异步操作:减少阻塞,提高响应性。
    • 投影查询:明确指定需要查询的字段,减少不必要的数据加载。
    • 预加载(Eager Loading):预先加载相关数据,减少后续的数据库访问。
    • NoTracking 查询:避免将查询结果附加到上下文,减少内存使用和提高查询性能。
    • 批量操作:进行批量插入、更新和删除操作,减少数据库操作的数量。
    • 配置连接池:确保数据库连接池配置正确,减少连接的开销。
    • 使用索引:确保在数据库中为常用查询字段创建索引,提高查询性能。

通过应用这些优化策略,可以显著提高 EF 和 EF Core 的性能,确保应用程序在处理大量数据和复杂查询时更加高效和响应迅速。

参考资源

Microsoft Docs - Entity Framework:
EF 文档
Microsoft Docs - Entity Framework Core:
EF Core 文档
EF Core 性能优化:
EF Core 性能优化指南
这些资源提供了详细的信息和示例,帮助你更好地理解和优化 EF 和 EF Core 的性能。

进一步优化建议

  1. 使用分页查询:

    • 对于大量数据的查询,使用分页(如 Skip 和 Take)来减少每次查询的数据量。

        public async Task<List<UserDto>> GetUsersPagedAsync(int pageNumber, int pageSize){return await _context.Users.Where(u => u.IsActive).Select(u => new UserDto{UserId = u.UserId,Name = u.Name}).Skip((pageNumber - 1) * pageSize).Take(pageSize).AsNoTracking().ToListAsync();}
      
  2. 使用 FromSqlRaw 或 FromSqlInterpolated:

    • 对于复杂的查询,可以使用原始 SQL 查询来提高性能。

        public async Task<List<UserDto>> GetUsersWithCustomQueryAsync(){var sql = "SELECT UserId, Name FROM Users WHERE IsActive = 1";return await _context.Users.FromSqlRaw(sql).Select(u => new UserDto{UserId = u.UserId,Name = u.Name}).ToListAsync();}
      
  3. 减少数据库上下文的生命周期:

    • 尽量减少 DbContext 的生命周期,避免长时间持有上下文。

        public class UserService{private readonly Func<ApplicationDbContext> _dbContextFactory;public UserService(Func<ApplicationDbContext> dbContextFactory){_dbContextFactory = dbContextFactory;}public async Task<List<UserDto>> GetAllActiveUsersDtoAsync(){using (var context = _dbContextFactory()){return await context.Users.Where(u => u.IsActive).Select(u => new UserDto{UserId = u.UserId,Name = u.Name}).AsNoTracking().ToListAsync();}}}
      
  4. 使用 CompiledQuery:

    • 对于频繁执行的查询,可以使用预编译查询来提高性能。

        private static readonly Func<ApplicationDbContext, int, Task<User>> _compiledQuery =EF.CompileAsyncQuery((ApplicationDbContext context, int userId) =>context.Users.Include(u => u.Orders).FirstOrDefault(u => u.UserId == userId));public async Task<User> GetUserWithOrdersCompiledQueryAsync(int userId){return await _compiledQuery(_context, userId);}
      
  5. 使用 QueryFilter:

    • 定义全局查询过滤器,减少每次查询的条件重复。

        protected override void OnModelCreating(ModelBuilder modelBuilder){modelBuilder.Entity<User>().HasQueryFilter(u => u.IsActive);}
      

总结

  1. EF 和 EF Core:

    • EF 主要用于 .NET Framework,而 EF Core 支持跨平台。
    • EF Core 在大多数情况下性能优于 EF,特别是在异步操作和跨平台支持方面。
  2. 优化策略:

    • 异步操作:减少阻塞,提高响应性。
    • 投影查询:明确指定需要查询的字段。
    • 预加载(Eager Loading):预先加载相关数据。
    • NoTracking 查询:避免将查询结果附加到上下文。
    • 批量操作:进行批量插入、更新和删除操作。
    • 配置连接池:确保数据库连接池配置正确。
    • 使用索引:确保在数据库中为常用查询字段创建索引。
    • 分页查询:减少每次查询的数据量。
    • 原始 SQL 查询:对于复杂查询使用原始 SQL。
    • 预编译查询:提高频繁执行查询的性能。
    • 全局查询过滤器:减少条件重复。
    • 通过这些优化策略,可以显著提高 EF 和 EF Core 的性能,确保应用程序在处理大量数据和复杂查询时更加高效和响应迅速。

参考资源

  • Microsoft Docs - EF Core 性能优化:
    EF Core 性能优化文档
  • Microsoft Docs - EF Core 连接池:
    EF Core 连接池文档
  • Microsoft Docs - EF Core 延迟加载:
    EF Core 延迟加载文档
  • Microsoft Docs - EF Core 预加载:

EF Core 预加载文档
这些资源提供了详细的信息和示例,帮助你更好地理解和优化 EF 和 EF Core 的性能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/864312.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

sql server版本太老,java客户端连接失败问题定位

背景 最近半路接手了一个系统的优化需求,这个系统有个遗留问题还没解决,随着新需求的上线,系统正式开放使用,这个遗留问题也必须解决。 这个系统大概是下面这样的,支持录入各种数据源的信息(ip、端口、数据库种类、账号密码等):录入完成后,可以查看这些数据源中的表、…

深入探索 Kubernetes:从基础概念到实战运维

前言:在当今数字化转型的浪潮中,Kubernetes 已然成为云原生应用部署与管理的核心力量。无论是初创企业寻求敏捷开发,还是大型企业应对复杂业务架构,掌握 Kubernetes 都能为你的技术之旅赋能。今天,就让我们一同深入 Kubernetes 的奇妙世界,揭开它神秘的面纱,从基础概念到…

Python 将html格式书签转为excel

1.导出html格式书签2.对数据做处理 提取 <a></a> 标签 可以用vscode正则替换 <a></a> 标签的ICON属性ICON=".*"3.安装python pip替换成清华镜像 4.描述问题生成代码 import pandas as pd from bs4 import BeautifulSoup from datetime i…

UML之发现用例

用例是最简单的UML元素,用例图是最简单的UML图,但它也可能是UML中最有用的元素之一。尽管我们用包将工作分解为工作包、团队任务或单项任务,也就是说包是组织UML中的各种图及元素的工具。但是用例图可以帮助我们确定任务,以及应当如何将它们分组并确定工作范围。 每个用例都…

遗留了很久的功能终于搞定/QTreeWidget自定义节点/添加删除修改分组

一、前言说明 这个功能看起来简单,实际上也确实简单,以前没搞的时候还以为很难,难点就是如何存储这个任意层级的树状列表信息,近期大环境经济很差,刚好有空把这个功能搞定,其实二维表格的方式存储这种任意层级树结构就可以,就是子节点需要指定父节点,父节点为空表示顶层…

2025年正在重塑行业的10款AI代理工具

序言:本文的作者列出来的这10款AI代理工具是您认可的吗? 作为一名深入AI开发领域超过十年的开发者,我见过无数工具声称要颠覆我们构建AI代理的方式。有些工具确实实现了夸下的海口——但更多的则没有。 经过几个月的亲身测试以及与同行开发者的讨论,我整理出了一份2025年真…

[cause]: TypeError: e_.createContext is not a function (Next.js 15)

开发 Next.js 项目遇到报错: [cause]: TypeError: e_.createContext is not a function 出现这个报错的原因是在 Next.js 项目中,在 Server Component 中使用了MUI组件,但是MUI组件没有做 SSR 适配就会导致这个报错。 解决办法 解决办法就是在文件顶部添加 use client 声明…

golang自带的死锁检测并非银弹

网上总是能看到有人说go自带了死锁检测,只要有死锁发生runtime就能检测到并及时报错退出,因此go不会被死锁问题困扰。 这说明了口口相传知识的有效性是日常值得怀疑的,同时也再一次证明了没有银弹这句话的含金量。 这个说法的杀伤力在于它虽然不对,但也不是全错,真真假假很…

2025多校冲刺省选模拟赛2

2025多校冲刺省选模拟赛2\(T1\) A. aw \(10pts/20pts\)部分分\(10 \sim 20pts\) :枚举每一种定向方案,略带卡常。点击查看代码 const int p=998244353; struct node {int nxt,to; }e[200010]; int head[100010],dis[1010][1010],a[100010],b[100010],g[2][100010],cnt=0; b…

jamovi 2.6 (Linux, macOS, Windows) - 统计软件

jamovi 2.6 (Linux, macOS, Windows) - 统计软件jamovi 2.6 (Linux, macOS, Windows) - 统计软件 open statistical software 请访问原文直链:https://sysin.org/blog/jamovi/ 查看最新版。原创作品,转载请保留出处。 作者主页:sysin.orgjamovi适用于桌面和云的开放式统计软…

读数据保护:工作负载的可恢复性26商用数据备份方案

商用数据备份方案1. 备份简史 1.1. 20世纪80年代中期大家都还没有意识到,运行着商用UNIX操作系统的大型工作环境里,应该配备一款商用的备份软件或某种自动的磁带系统 1.2. 1993年备份工作全都是通过shell脚本与cron job形式的计划任务来实现的1.2.1. 脚本总是假定服务器中需要…

OpenCV和OpenVX有什么联系和区别

OpenCV和OpenVX有什么联系和区别 联系和区别是:OpenCV是一个基于Apache2.0许可(开源)发行的跨平台计算机视觉和机器学习软件库。OpenVX 实现了跨平台加速处理,OpenVX在嵌入式和实时性系统中,可以更好地发挥它的优势,在某些场合配合OpenCV的强大功能,可以实现更好的效果。…