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

EF Core更新Courses表时报错:实体类型'List<Course>'未找到

问题描述

更新数据库Courses表字段时触发错误:

The entity type 'List' was not found. Ensure that the entity type has been added to the model.

需求:根据复选框状态,将选中为讲师著作的课程的Course.AuthorId设为当前讲师Id;选中为编辑者的课程的Course.EditorId设为当前讲师Id,未选中则置空对应字段。


控制器方法

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> EditInstructorCourse(int id, List<EditInstructorCourseViewModel> model)
{
        if (_context.Courses is null)
        {
            return NotFound();
        }

        var courses = await _context.Courses.ToListAsync();

        try
        {
            for (int i = 0; i < model.Count; i++)
            {
                if (model[i].IsAuthor = true)
                {
                    courses[i].AuthorId = id;
                    _context.Update(courses);
                }
                else
                {
                    courses[i].AuthorId = null;
                }
            }

            _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            throw;
        }

        return RedirectToAction(nameof(Index));
}

视图模型

public class EditInstructorCourseViewModel
{
    public string CourseId { get; set; }
    public string CourseName { get; set; }
    public string CourseAuthor { get; set; }
    public string CourseEditor { get; set; }

    public bool IsAuthor { get; set; }
    public bool IsEditor { get; set; }
}

实体类

public class Instructor
{
    public int Id { get; set; }

    [DisplayName("Instructor")]
    public string InstructorName { get; set; }

    [ForeignKey("AuthorId")]
    [DisplayName("Author Of")]
    public ICollection<Course> CoursesAuthored { get; set; } = new List<Course>();

    [ForeignKey("EditorId")]
    [DisplayName("Editor Of")]
    public List<Course> CoursesEdited { get; set; } = new List<Course>();
}

public class Course
{
    public int Id { get; set; }

    [DisplayName("Course")]
    public string CourseName { get; set; }

    public int? AuthorId { get; set; }
    public Instructor? Author { get; set; }
    public int? EditorId { get; set; }
    public Instructor? Editor { get; set; }
}

Fluent API配置

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Course>()
        .HasOne(course => course.Editor)
        .WithMany(editor => editor.CoursesEdited)
        .HasForeignKey(course => course.EditorId);

    modelBuilder.Entity<Course>()
        .HasOne(course => course.Author)
        .WithMany(editor => editor.CoursesAuthored)
        .HasForeignKey(course => course.AuthorId);
}

视图代码

@model List<OneToManyMany.Models.ViewModels.EditInstructorCourseViewModel>

@{
    var instructorId = ViewData["InstructorId"];
    var instructorName = ViewData["InstructorName"];
}

<h2>Edit Courses for <strong> @instructorName</strong></h2>


<div class="form-group">
    <label asp-for="@instructorName" class="control-label"></label>
    <input asp-for="@instructorName" class="form-control" />
    <span asp-validation-for="@instructorName" class="text-danger"></span>
</div>

<div>
    <form asp-action="EditInstructorCourse" method="post">
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>
        <input type="hidden" asp-for="@instructorId" />
        <div class="form-group">
            <h5>Author Of</h5>
            @for (int i = 0; i < Model.Count; i++)
            {
                <div class="form-check m-1">
                    <input type="hidden" asp-for="@Model[i].CourseId" />
                    <input type="hidden" asp-for="@Model[i].CourseName" />
                    <input asp-for="@Model[i].IsAuthor" class="form-check-input" />
                    <label class="form-check-label" asp-for="@Model[i].IsAuthor">
                        @Model[i].CourseName
                    </label>
                </div>
            }
        </div>
        <div class="form-group">
            <h5>Editor Of</h5>
            @for (int i = 0; i < Model.Count; i++)
            {
                <div class="form-check m-1">
                    <input type="hidden" asp-for="@Model[i].CourseId" />
                    <input type="hidden" asp-for="@Model[i].CourseName" />
                    <input asp-for="@Model[i].IsEditor" class="form-check-input" />
                    <label class="form-check-label" asp-for="@Model[i].IsEditor">
                        @Model[i].CourseName
                    </label>
                </div>
            }
        </div>
        <div class="mt-4">
            <a asp-controller="Instructors" asp-action="Index" asp-route-id="@instructorId" class="btn btn-secondary me-2">Cancel</a>
            <button id="saveBtn" type="submit" class="btn btn-primary">Save</button>
        </div>
    </form>
    <hr />
</div>

解决方案

核心错误修正

  1. 错误的Update调用:_context.Update(courses)传入了List<Course>,但Update方法仅接受单个实体。且从数据库查询的courses已被上下文跟踪,修改属性后无需手动调用Update,上下文会自动追踪变更。
  2. 赋值而非判断:if (model[i].IsAuthor = true)是赋值操作,应改为if (model[i].IsAuthor)或if (model[i].IsAuthor == true)。
  3. 异步方法未加await:_context.SaveChangesAsync()是异步方法,必须添加await关键字,否则操作未完成就会跳转。
  4. 实体匹配逻辑错误:直接按索引i匹配model和courses不安全,两者顺序可能不一致,应通过CourseId关联对应课程。
  5. 视图参数传递错误:asp-for="@instructorId"无效,因为instructorId是ViewData中的值,不是模型属性,需改为普通hidden input传递讲师Id到控制器的id参数。

修正后的控制器代码

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> EditInstructorCourse(int id, List<EditInstructorCourseViewModel> model)
{
    if (_context.Courses is null)
    {
        return NotFound();
    }

    // 用CourseId建立字典,快速匹配课程
    var courseDict = await _context.Courses
        .ToDictionaryAsync(c => c.Id.ToString());

    try
    {
        foreach (var item in model)
        {
            if (courseDict.TryGetValue(item.CourseId, out var course))
            {
                // 处理作者字段
                course.AuthorId = item.IsAuthor ? id : null;
                // 处理编辑者字段
                course.EditorId = item.IsEditor ? id : null;
            }
        }

        await _context.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException)
    {
        throw;
    }

    return RedirectToAction(nameof(Index));
}

修正后的视图关键部分

将原视图中的讲师Id隐藏输入替换为:

<input type="hidden" name="id" value="@instructorId" />

同时移除无效的讲师名称输入块(视图模型无对应属性,无需修改):

<!-- 移除以下无效代码 -->
<div class="form-group">
    <label asp-for="@instructorName" class="control-label"></label>
    <input asp-for="@instructorName" class="form-control" />
    <span asp-validation-for="@instructorName" class="text-danger"></span>
</div>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 00:29:50