ModelState.IsValid 包含导航 属性。总是假的。 (仅限net-6.0) 怎么弄成真?

ModelState.IsValid includes a navigation property. Always false. (only net-6.0) How to get true?

这是 dotnet 上的示例。 github.com/dotnet... 我在 net-6.0 版本上工作

验证检查的结果为 false,因为 class 的导航属性参与了验证。 我在 net-5.0 上实现了一个简单的实验——导航属性没有反映在结果中。但是,也许我错了。

如何正确解决这个问题?

public class Course
{
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    [Display(Name = "Number")]
    public int CourseID { get; set; }

    [StringLength(50, MinimumLength = 3)]
    public string Title { get; set; }

    [Range(0, 5)]
    public int Credits { get; set; }

    public int DepartmentID { get; set; }

    public Department Department { get; set; }
    public ICollection<Enrollment> Enrollments { get; set; }
    public ICollection<CourseAssignment> CourseAssignments { get; set; }
}

CoursesController.cs

// POST: Courses/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for 
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(
    [Bind("CourseID,Credits,DepartmentID,Title")] Course course)
{
    if (ModelState.IsValid)
    {
        _context.Add(course);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }
    PopulateDepartmentsDropDownList(course.DepartmentID);
    return View(course);
}

验证结果

不确定这是否回答了您的问题。但建议您 创建一个 Data Transfer Object (DTO) class 而不是直接使用(生成的)数据库对象 class.

DTO class 是根据 API 预期接收的值(架构)设计的。并且这个 DTO class 还将用于执行 first-level 数据验证,例如 Required、Range 等(不涉及对数据库的验证)

public class CreateCourseDto
{
    [Display(Name = "Number")]
    public int CourseID { get; set; }

    [StringLength(50, MinimumLength = 3)]
    public string Title { get; set; }

    [Range(0, 5)]
    public int Credits { get; set; }

    public int DepartmentID { get; set; }
}

然后只将DTO 中的值绑定到真正的DB 对象。手动 bind/assign 值或应用 tool/library 例如 AutoMapper.

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(
    [Bind("CourseID,Credits,DepartmentID,Title")] CreateCourseDto course)
{
    if (ModelState.IsValid)
    {
        // Map received course value to DB object 
        Course _course = new Course
        {
            CourseID = course.CourseID,
            Title = course.Title,
            Credits = course.Credits, 
            DepartmentID = course.DepartmentID
        };

        _context.Add(_course);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }
    PopulateDepartmentsDropDownList(course.DepartmentID);
    return View(course);
}

我认为问题出在新的可空功能 net6。我强烈建议您将其删除或在项目属性中发表评论

 <!--<Nullable>enable</Nullable>-->

这是一个非常愚蠢的功能。在生命结束之前,您必须将所有属性标记为可为空。

public ICollection<CourseAssignment>? CourseAssignments { get; set; }

恕我直言,从不在控制器操作参数中使用绑定。你总是会遇到问题。它只在剃须刀页面中有用,但在非常非常罕见的情况下。并在极少数情况下使用 Dto。当我必须从连接创建最多的属性时,我通常只将 Dto 用于 select。