ASP.NET MVC中Include()方法用法及关联数据加载问题解答
Entity Framework 中
Include()方法使用说明 核心作用
Include()是EF(Entity Framework、EF Core)提供的**贪婪加载(预加载)**API,作用是查询主实体数据时,通过SQL JOIN一次性拉取指定关联导航属性的数据,避免后续访问关联属性时产生额外数据库查询,解决常见的N+1查询性能问题。
具体使用方式
- 字符串参数重载:即你当前代码使用的写法,直接传入导航属性的名称字符串,例如
Include("Images")代表加载Product关联的图片集合。这种写法兼容所有EF版本,但缺点是属性名拼写错误、属性重命名时不会触发编译报错,运行时才会抛出异常。 - 强类型Lambda重载(推荐):新版本EF/EF Core支持通过Lambda表达式指定导航属性,例如
Include(p => p.Images)。这种写法可以在编译期检查属性合法性,重构属性名时IDE会同步修改,不会出现字符串硬编码的错误。 - 多级关联加载:如果需要加载关联属性下的次级关联,可以在
Include()后链式调用ThenInclude(),例如要加载商品分类的上级分类,可以写Include(p => p.Category).ThenInclude(c => c.ParentCategory)。 - 支持的导航属性类型:无论是集合类型导航属性(比如你Product模型中定义的
List<ProdImage> Images,一个商品对应多张图片),还是单实体引用导航属性(比如Category、Format,一个商品对应一个分类/格式),都可以通过Include()指定预加载。
是否必须通过Include()加载关联属性
不是必须的,完全取决于业务场景和EF的配置:
- 不需要使用
Include()的场景:- 业务逻辑后续根本不会访问对应导航属性的数据:这时候加
Include()反而会生成多余的表关联查询,拉取无用字段,降低查询性能。 - 开启了延迟加载(Lazy Loading):此时即使不写
Include(),后续代码第一次访问导航属性时,EF会自动发送单独的SQL查询拉取关联数据。但要注意如果遍历商品列表再逐个访问关联属性,会产生N+1查询问题,性能损耗非常大。
- 业务逻辑后续根本不会访问对应导航属性的数据:这时候加
- 建议/必须使用
Include()的场景:- 关闭了延迟加载,且需要在DbContext释放后(比如查询方法返回、数据库连接关闭后)访问关联属性:这种场景下不写
Include()的话,导航属性会是null或者空集合,无法获取到关联数据。 - 确定后续逻辑需要用到关联属性数据:用
Include()预加载可以一次性通过JOIN拉取所有需要的数据,减少数据库往返次数,性能远高于延迟加载。
- 关闭了延迟加载,且需要在DbContext释放后(比如查询方法返回、数据库连接关闭后)访问关联属性:这种场景下不写
针对你提供代码的说明
你当前的代码是典型的预加载写法,在查询商品时提前加载了标签、图片、分类、格式等关联数据,适合接口返回商品完整信息的场景,避免后续访问关联属性报错或产生额外查询。
注意:你目前使用的是字符串传参的写法,后续如果重命名导航属性(比如把Images改成ProductImages),硬编码的字符串不会同步更新,会导致运行时报错,建议替换为强类型Lambda写法,示例如下:
public IEnumerable<Product> GetAll(int Productstate) { return db.Products .Include(p => p.Tags) .Include(p => p.Images) .Include(p => p.Category) .Include(p => p.Format) .Where(pl => pl.state > 0) .Where(p => p.state >= Productstate); } public Product Get(Int64 id) { return db.Products .Include(p => p.Images) .Include(p => p.Category) .Where(PPR => PPR.Id == id) .FirstOrDefault(); }
内容的提问来源于stack exchange,提问作者Ann
相关产品推荐
相关产品推荐

