You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Razor Pages项目中EF无法访问Case外键属性问题排查

问题:Entity Framework关联Case属性无法在Razor Pages视图中显示

问题场景

在Razor Pages项目中,通过Entity Framework关联实体显示外键属性值时,Issue关联的Specialist属性(如FullName、Laboratory)能正常渲染,但Case的属性(如CaseNumber、Principal)无内容展示。

相关代码如下:

视图代码

@foreach (var item in Model.UserIssues)
{
    <div class="card scroll" style="width:22rem;">
        <div class="card-header p-4">
            <div class="d-flex justify-content-between">
                <div>
                    <p class="card-label mb-0"></p>
                    <h5>@Html.DisplayFor(i => item.Case.CaseNumber)</h5>
                </div>
                <div>
                    <a class="btn button-idle-add" data-bs-toggle="tooltip" data-bs-title="Dodaj Pracownię" asp-route-id="@item.Id" asp-page="/Cases/AddLaboratory"><i class="fa-solid fa-plus"></i></a>
                </div>
            </div>
            <div class="d-flex justify-content-between mt-3">
                <div>
                    <p class="card-input">@Html.DisplayFor(e => item.Case.Principal)</p>
                </div>
                <div>
                    <p class="card-input">@Html.DisplayFor(e => item.Case.Date)</p>
                </div>
            </div>
        </div>
        <div class="card-body">
            <div class="m-1 p-3 card-lab">
                <div class="d-flex justify-content-between align-items-center">
                    <p>@Html.DisplayFor(e => item.IssueNumber)</p>
                    <p class="pe-3 ps-3" style="border-radius:15px; background-color: palegreen;"></p>
                </div>
                <p>@Html.DisplayFor(e => item.Specialist.Laboratory)</p>
                <p>@Html.DisplayFor(e => item.Specialist.FullName)</p>
            </div>
        </div>
    </div>
}

PageModel代码

public class IndexModel : PageModel
{
    private readonly IRepository<Issue> issueRepository;
    private readonly IRepository<Specialist> specialistRepository;

    public IndexModel(IRepository<Issue> issueRepository, IRepository<Specialist> specialistRepository)
    {
        this.issueRepository = issueRepository;
        this.specialistRepository = specialistRepository;
    }

    public List<Issue> UserIssues { get; set; }

    public async Task<IActionResult> OnGetAsync()
    {
        var loggedUser = specialistRepository.GetAll().FirstOrDefault(u => u.Login == User.Identity.Name);

        UserIssues = issueRepository.GetAll().Where(i => i.Specialist.Id == loggedUser.Id).ToList();

        return Page();
    }
}

实体模型代码

Case类

public class Case
{
    [Key]
    public int Id { get; set; }

    [Required(ErrorMessage = "Uzupełnij pole")]
    public string CaseNumber { get; set; }

    [Required(ErrorMessage = "Uzupełnij pole")]
    public string Principal { get; set; }

    [Required(ErrorMessage = "Uzupełnij pole")]
    public string Description { get; set; }

    [Required(ErrorMessage = "Uzupełnij pole")]
    public string Date { get; set; }

    public ICollection<Issue> Issues { get; set; }
}

Issue类

public class Issue
{
    [Key]
    public int Id { get; set; }

    public string Comment { get; set; }

    [Required(ErrorMessage = "Uzupełnij pole")]
    public string IssueNumber { get; set; }

    public Case Case { get; set; }

    public Specialist Specialist { get; set; }
}

Specialist类

public class Specialist : IdentityUser
{
    [Required]
    public string Login { get; set; }
    [Required]
    public string FirstName { get; set; }
    [Required]
    public string LastName { get; set; }
    [Required]
    public string Laboratory { get; set; }

    public string FullName
    {
        get
        {
            return FirstName + " " + LastName;
        }
    }

    public ICollection<Issue> Issues { get; set; }
}

问题原因

  1. 缺少显式外键字段:Issue实体仅定义了Case导航属性,但未添加对应的CaseId外键字段。Entity Framework默认需要外键明确关联关系,缺少外键可能导致关联数据无法正确映射。
  2. 未显式加载关联实体:查询Issue时未使用Include方法加载关联的Case数据。如果仓库的GetAll()方法未处理关联加载,且延迟加载未开启,EF不会自动获取Case的相关数据。

解决方案

步骤1:为Issue实体添加外键字段

修改Issue类,添加CaseId外键(同时建议为Specialist添加外键,保持一致性):

public class Issue
{
    [Key]
    public int Id { get; set; }

    public string Comment { get; set; }

    [Required(ErrorMessage = "Uzupełnij pole")]
    public string IssueNumber { get; set; }

    // 添加Case外键
    public int CaseId { get; set; }
    public Case Case { get; set; }

    // 添加Specialist外键(IdentityUser主键为string)
    public string SpecialistId { get; set; }
    public Specialist Specialist { get; set; }
}

步骤2:更新数据库

添加外键后,生成新的EF迁移并更新数据库,确保数据库表中新增CaseId和SpecialistId字段:

Add-Migration AddForeignKeysToIssue
Update-Database

步骤3:查询时显式加载关联实体

修改PageModel中的查询逻辑,使用Include方法加载Case和Specialist关联数据。如果仓库的GetAll()返回IQueryable<T>,可直接链式调用:

public async Task<IActionResult> OnGetAsync()
{
    var loggedUser = specialistRepository.GetAll().FirstOrDefault(u => u.Login == User.Identity.Name);

    UserIssues = issueRepository.GetAll()
                                .Include(i => i.Case) // 加载关联的Case
                                .Include(i => i.Specialist) // 显式加载Specialist(确保稳定性)
                                .Where(i => i.Specialist.Id == loggedUser.Id)
                                .ToList();

    return Page();
}

如果仓库的GetAll()返回List<T>而非IQueryable<T>,需要修改仓库接口和实现,支持关联加载:

扩展IRepository接口

public interface IRepository<T>
{
    IQueryable<T> GetAll();
    // 添加支持关联加载的方法
    IQueryable<T> GetAllIncluding(params Expression<Func<T, object>>[] includes);
}

实现仓库方法

public class IssueRepository : IRepository<Issue>
{
    private readonly ApplicationDbContext _context;

    public IssueRepository(ApplicationDbContext context)
    {
        _context = context;
    }

    public IQueryable<Issue> GetAll()
    {
        return _context.Issues.AsQueryable();
    }

    public IQueryable<Issue> GetAllIncluding(params Expression<Func<Issue, object>>[] includes)
    {
        var query = _context.Issues.AsQueryable();
        foreach (var include in includes)
        {
            query = query.Include(include);
        }
        return query;
    }
}

修改PageModel调用

UserIssues = issueRepository.GetAllIncluding(i => i.Case, i => i.Specialist)
                            .Where(i => i.Specialist.Id == loggedUser.Id)
                            .ToList();

可选:验证延迟加载配置

如果希望依赖延迟加载(不推荐用于查询场景,会导致N+1问题),需确保EF上下文已开启延迟加载:

public class ApplicationDbContext : IdentityDbContext<Specialist>
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
        // 开启延迟加载(需安装Microsoft.EntityFrameworkCore.Proxies包)
        this.ChangeTracker.LazyLoadingEnabled = true;
    }

    public DbSet<Case> Cases { get; set; }
    public DbSet<Issue> Issues { get; set; }
}

验证

完成上述修改后,重新运行项目,视图中Case的相关属性(CaseNumber、Principal等)即可正常显示。

内容的提问来源于stack exchange,提问作者Just Nicolas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 22:11:04