如何正确使用EF Eager Loading?ASP.NET MVC关联加载报错解决
ReqLpu_Id错误&正确配置关联关系 看起来你在EF的实体关系配置上搞反了方向,这才导致了那个SqlException: invalid column name "ReqLpu_Id"的错误。咱们一步步拆解问题,把Eager Loading用对:
核心问题分析
你的需求是用ReqLpu.STATUS关联ReqStatusMO.IdStat,显示ReqLpu数据时把STATUS替换成对应的状态名称,这本质是一个多对一关系:多个请求(ReqLpu)可以属于同一个状态(ReqStatusMO)。但你之前的Fluent API配置把关系搞反了,还指定了不存在的外键属性,EF找不到你配置的列,就自动生成了默认的外键列名ReqLpu_Id,而数据库里没有这个列,所以报错。
1. 修正实体模型
ReqLpu模型(主表)
把原来的集合导航属性改成单个的状态导航属性(一个请求只有一个状态):
public class ReqLpu { [Key] public int IdLpu { get; set; } public string COD { get; set; } public string M_NAMES { get; set; } public string TEL { get; set; } public string FAX { get; set; } public string E_MAIL { get; set; } public int? STATUS { get; set; } // 多对一:一个ReqLpu对应一个ReqStatusMO public virtual ReqStatusMO ReqStatusMO { get; set; } }
ReqStatusMO模型(状态表)
添加集合导航属性(一个状态对应多个请求),并确保属性是public(EF需要识别它):
public class ReqStatusMO { [Key] public int IdStat { get; set; } public string Name { get; set; } // 一对多:一个ReqStatusMO对应多个ReqLpu public virtual ICollection<ReqLpu> ReqLpus { get; set; } }
2. 修正Fluent API配置
在OnModelCreating里配置正确的多对一关系,明确指定ReqLpu.STATUS是关联到ReqStatusMO.IdStat的外键:
public class WorksContext :DbContext { public DbSet<ReqLpu> ReqLpus { get; set; } public DbSet<ReqStatusMO> ReqStatusMOs { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity<ReqLpu>().ToTable("ReqLpu"); modelBuilder.Entity<ReqStatusMO>().ToTable("ReqStatusMO"); // 配置多对一关系:ReqLpu的STATUS是外键,对应ReqStatusMO的IdStat modelBuilder.Entity<ReqLpu>() .HasOptional(r => r.ReqStatusMO) // 因为STATUS是int?,所以是可选关联 .WithMany(s => s.ReqLpus) .HasForeignKey(r => r.STATUS) .HasPrincipalKey(s => s.IdStat); } }
如果你的
STATUS是必填项(非可空),把HasOptional改成HasRequired即可。
3. 控制器代码(Eager Loading用法正确,无需大改)
原来的Include写法是对的,保持不变:
lpuv = wk.ReqLpus.Include(p => p.ReqStatusMO).ToList(); return View(lpuv);
4. 修正视图代码
现在导航属性是单个对象,不需要用Select,直接访问Name即可,记得处理状态为空的情况:
@model IEnumerable<LpuList.Models.ReqLpu> ... <table class="table"> <tr> <th> @Html.DisplayNameFor(model => model.M_NAMES) </th> <th>@Html.DisplayName("状态")</th> ... </tr> @foreach (var item in Model) { <tr> @Html.HiddenFor(modelItem => item.IdLpu) <!-- 注意这里是IdLpu,不是Id --> <td> @Html.DisplayFor(modelItem => item.M_NAMES) </td> ... <td> @(item.ReqStatusMO != null ? item.ReqStatusMO.Name : "无状态") </td> <td> ... </td> </tr> } </table>
为什么原来的配置会出错?
你之前的Fluent API配置是让ReqStatusMO依赖于ReqLpu,相当于“状态属于某个请求”,这完全不符合你的业务逻辑。正确的逻辑是“请求属于某个状态”,所以关系方向必须反过来,EF才能正确映射数据库列,不会生成莫名其妙的ReqLpu_Id列。
内容的提问来源于stack exchange,提问作者袗薪写褉械泄 袚芯谢褍斜褑芯胁

