EF Core自引用关系:Details视图Child为Null但Index视图正常
问题排查:Contact自引用关系中Details方法无法访问Child的FullName
我为Contact模型设置了自引用关系(一个联系人可与其他联系人建立关联)。在控制器的GET: Details方法中,能获取到ChildId,但无法访问Child对应的Contact的FullName;而GET Index方法中Child不为Null,可正常访问FullName。
控制器代码
Details方法查询
var contact = await _context.Contacts .Include(r => r.RelationshipsAsParent) .ThenInclude(t => t.RelationshipType) .FirstOrDefaultAsync(m => m.Id == id);
Index方法查询
return _context.Contacts != null ? View(await _context.Contacts .Include(r => r.RelationshipsAsParent) .ThenInclude(t => t.RelationshipType) .ToListAsync()) : Problem("Entity set 'ApplicationDbContext.Contacts' is null.");
模型代码
public class Contact { public int Id { get; set; } public string? FirstName { get; set; } public string? LastName { get; set; } [NotMapped] public string? FullName { get { return $"{FirstName} {LastName}"; } } // Navigation properties for relationships where this contact is the parent public virtual List<Relationship>? RelationshipsAsParent { get; set; } // Navigation properties for relationships where this contact is the child public virtual List<Relationship>? RelationshipsAsChild { get; set; } } public class Relationship { public int Id { get; set; } public int? ParentId { get; set; } public virtual Contact? Parent { get; set; } // Foreign key and navigation property for the child contact public int? ChildId { get; set; } public virtual Contact? Child { get; set; } // Navigation property for the relationship type (assuming there's a RelationshipType entity) public int? RelationshipTypeId { get; set; } public virtual RelationshipType? RelationshipType { get; set; } } public class RelationshipType { public int Id { get; set; } public string? Type { get; set; } public virtual List<Relationship>? Relationships { get; set; } = new List<Relationship>(); }
Fluent API配置
modelBuilder.Entity<Relationship>(b => { modelBuilder.Entity<Relationship>() .HasOne(r => r.Parent) .WithMany(c => c.RelationshipsAsParent) .HasForeignKey(r => r.ParentId) .OnDelete(DeleteBehavior.Restrict); modelBuilder.Entity<Relationship>() .HasOne(r => r.Child) .WithMany(c => c.RelationshipsAsChild) .HasForeignKey(r => r.ChildId) .OnDelete(DeleteBehavior.Restrict); });
视图代码
Detail视图
<h3>Relationships</h3> <ul> @if (@Model.RelationshipsAsParent.Count > 0) { @for (int j = 0; j < Model.RelationshipsAsParent.Count; j++) { <li>@Model.RelationshipsAsParent[j].ChildId: @Model.RelationshipsAsParent[j].RelationshipType.Type</li> } } else { <li>No Relationships</li> } </ul>
Index视图
<div class="row ms-5"> <ul> @if (item.RelationshipsAsParent != null) { @for (int j = 0; j < item.RelationshipsAsParent.Count; j++) { <li>@item.RelationshipsAsParent[j].Child.FullName: @item.RelationshipsAsParent[j].RelationshipType.Type</li> } } else { <li>No Relationships</li> } </ul> </div>
问题原因及解决办法
问题核心是显式加载范围不足,结合延迟加载的触发条件导致差异:
- Index方法查询所有Contact时,Child对应的Contact实例已被加载到上下文,延迟自动触发,
Child导航属性可正常访问;而Details方法仅查询单个Contact,上下文无对应Child实例,且未显式IncludeChild导航属性,因此Child为Null。 - 解决办法是在Details方法的查询中,显式加载
Relationship的Child导航属性:
修改后的Details方法查询:
var contact = await _context.Contacts .Include(r => r.RelationshipsAsParent) .ThenInclude(t => t.RelationshipType) .Include(r => r.RelationshipsAsParent) .ThenInclude(t => t.Child) // 新增此行,显式加载Child .FirstOrDefaultAsync(m => m.Id == id);
或使用EF Core 5+支持的简洁语法:
var contact = await _context.Contacts .Include(r => r.RelationshipsAsParent) .ThenInclude(t => new { t.RelationshipType, t.Child }) .FirstOrDefaultAsync(m => m.Id == id);
修改后即可确保RelationshipsAsParent中每个Relationship的Child被加载,视图里就能正常访问Child.FullName。
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

