使用其他字段在ASP.Net Core控制器中编辑操作

时间:2018-04-17 04:11:35

标签: c# asp.net-core-mvc entity-framework-core asp.net-core-2.0

我的表格中有一个URL字段用于每个课程。我正在使用它作为路由参数。我这样做是为了让Urls用户友好,根据我的理解,这也可以帮助我在SEO(请纠正我,如果我错了)。有了这样的设置,我无法弄清楚如何创建编辑/删除操作。

Course.cs:课程模型

public partial class Course
{
    public int Id { get; set; }
    public string Title { get; set; }
    // This is set as Unique Key in the table. 
    public string Url { get; set; }
    public string InnerHtml { get; set; }
}

CourseController.cs:控制器和编辑操作,供我们参考。

    [HttpPost("Edit/{courseUrl}")]
    [ValidateAntiForgeryToken]
    [Authorize(Roles = "Administrator")]
    public async Task<IActionResult> Edit(string courseUrl, [Bind("Id,Title,Url,InnerHtml")] Course course)
    {

        var OriginalCourse = await _context.Courses.SingleOrDefaultAsync(m => m.Url == courseUrl);

        if (OriginalCourse.Id != course.Id)
        {
            return NotFound();
        }

        if (ModelState.IsValid)
        {
            try
            {
                _context.Update(course);
                await _context.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!CourseExists(course.Url))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                }
            }
            return RedirectToAction(nameof(Index));
        }
        return View(course);
    }

问题:我在此操作中收到以下错误

  

InvalidOperationException:实体类型的实例&#39; Course&#39;无法跟踪,因为已经跟踪了具有{&#39; Id&#39;}的相同键值的另一个实例。附加现有实体时,请确保仅附加具有给定键值的一个实体实例。考虑使用&#39; DbContextOptionsBuilder.EnableSensitiveDataLogging&#39;查看冲突的键值。

WorkAround:在操作中评论以下代码,让应用程序正常工作。但是,下面的代码是检查正在编辑的模型是否包含在DB中。

        var OriginalCourse = await _context.Courses.SingleOrDefaultAsync(m => m.Url == courseUrl);

        if (OriginalCourse.Id != course.Id)
        {
            return NotFound();
        }

处理这种情况的正确方法是什么?

1 个答案:

答案 0 :(得分:2)

正如错误消息所解释的那样,已经有一个从ORM跟踪的搜索中加载的模型。如果要保存它,则需要将所需的属性复制到跟踪的模型。

//...code removed for brevity

var OriginalCourse = await _context.Courses.SingleOrDefaultAsync(m => m.Url == courseUrl);

if (OriginalCourse.Id != course.Id) {
    return NotFound();
}

if (ModelState.IsValid) {
    try {
        Populate(OriginalCourse, course);

        _context.Update(OriginalCourse);
        await _context.SaveChangesAsync();
    } catch (DbUpdateConcurrencyException) {
        if (!CourseExists(course.Url)) {
            return NotFound();
        } else {
            throw;
        }
    }
    return RedirectToAction(nameof(Index));
}

//...code removed for brevity

Populate看起来像这样

void Populate(Course original, Cource source) {
    original.Title = source.Title;
    original.Url = source.Url;
    original.InnerHtml = source.InnerHtml;
}

另一个选择是不通过不从上下文中选择/返回项目来加载实例

//...code removed for brevity

var exists = await _context.Courses.AnyAsync(m => m.Url == courseUrl);

if (!exists) {
    return NotFound();
}

//...code removed for brevity

然后更新提供的课程