如何用Entity Framework和C#高效获取记录并优化GuestName加载
优化Booking加载性能方案
你的Load方法耗时20秒的核心原因是N+1数据库查询问题:循环中每个Booking都发起两次数据库请求(Any和GetName),如果有大量Booking,会产生数百次数据库调用,严重拖慢速度。下面是无需foreach循环的高效优化方案:
一、先修正EF实体关联(推荐方案)
给数据库实体Data.Tables.Booking添加Guest导航属性,让EF能直接关联查询:
[Table("Bookings")] public class Booking : ITrackable { // 原有属性保持不变 [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } public int GuestId { get; set; } // 添加Guest导航属性,指定外键关联 [ForeignKey("GuestId")] public virtual Guest Guest { get; set; } // 其他原有属性... }
二、配置AutoMapper映射GuestName
修改你的AutoMapper配置,让它直接从导航属性映射GuestName(假设Guest实体有Name属性):
public class MappingProfile : Profile { public MappingProfile() { CreateMap<Data.Tables.Booking, Booking>() // 从关联的Guest实体中获取Name赋值给GuestName .ForMember(dest => dest.GuestName, opt => opt.MapFrom(src => src.Guest.Name)); } }
三、优化Load方法(一次性查询所有数据)
使用EF的Include预加载Guest数据,避免循环查询:
public List<Booking> Load(int roomId) { var result = _context.Bookings // 预加载关联的Guest数据,一次性从数据库取出 .Include(b => b.Guest) .Where(b => b.RoomId == roomId) .Select(b => _mapper.Map<Booking>(b)) .ToList(); return result; }
备选方案:不修改实体,用Join查询
如果不想修改实体结构,可以直接用Join方式一次性关联查询:
public List<Booking> Load(int roomId) { var result = _context.Bookings .Join( _context.Guests, booking => booking.GuestId, guest => guest.Id, (booking, guest) => new { Booking = booking, GuestName = guest.Name } ) .Where(x => x.Booking.RoomId == roomId) .Select(x => { var model = _mapper.Map<Booking>(x.Booking); model.GuestName = x.GuestName; return model; }) .ToList(); return result; }
额外优化建议
- 添加数据库索引:给
Bookings.RoomId和Bookings.GuestId字段添加索引,加速查询过滤和关联。 - 缓存Guest数据:如果Guest信息不频繁更新,可以用内存缓存(如
IMemoryCache)缓存Guest的Id-Name映射,进一步减少数据库查询。 - 移除冗余判断:原代码中的
_context.Guests.Any()完全多余,若数据库有外键约束,GuestId必然对应有效Guest,直接获取Name即可。
内容的提问来源于stack exchange,提问作者don
相关产品推荐
相关产品推荐

