C# 控制器正在使用空值填充对象,尽管它们未被绑定

C# 控制器正在使用空值填充对象,尽管它们未被绑定,c#,asp.net-mvc,entity-framework,model-view-controller,C#,Asp.net Mvc,Entity Framework,Model View Controller,我仍然在学习很多关于实体框架及其通信方式的知识,因此这可能是一个简单的问题,但我似乎无法找出问题所在 要设置场景,我有一个由Visual Studio生成的工作创建函数,并且我在该函数中设置了如下值: myObject.Id = Guid.NewGuid().ToString(); myObject.dateCreated = DateTime.Now; 这看起来很棒,一切都正常工作。当我试图编辑记录时,问题就出现了 我有这个模型: public class MyObject { pu

我仍然在学习很多关于实体框架及其通信方式的知识,因此这可能是一个简单的问题,但我似乎无法找出问题所在

要设置场景,我有一个由Visual Studio生成的工作创建函数,并且我在该函数中设置了如下值:

myObject.Id = Guid.NewGuid().ToString();
myObject.dateCreated = DateTime.Now;
这看起来很棒,一切都正常工作。当我试图编辑记录时,问题就出现了

我有这个模型:

public class MyObject
{
    public string Id { get; set; }
    public string UserId { get; set; }
    public string Name { get; set;  }
    public DateTime dateCreated { get; set; }
    public Nullable<DateTime> dateModified { get; set; }
    public Boolean aDefault { get; set; }

}
公共类MyObject
{
公共字符串Id{get;set;}
公共字符串用户标识{get;set;}
公共字符串名称{get;set;}
public DateTime dateCreated{get;set;}
公共可为空的dateModified{get;set;}
公共布尔值{get;set;}
}
(大部分是自动生成的)这些控制器:

public async Task<ActionResult> Edit(string id)
{
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
    MyObject myObject = await db.myObjects.FindAsync(id);
    if (myObject == null)
    {
        return HttpNotFound();
    }
    return View(myObject);
}

public async Task<ActionResult> Edit([Bind(Include = "Id,aDefault,Name")] MyObject myObject)
{
    if (ModelState.IsValid)
    {
        myObject.dateModified = DateTime.Now;
        db.Entry(myObject).State = EntityState.Modified;
        await db.SaveChangesAsync(); //db is the generated dbcontext
        return RedirectToAction("Index");
    }
    return View(myObject);
}
公共异步任务编辑(字符串id)
{
if(id==null)
{
返回新的HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
MyObject MyObject=wait db.myObjects.FindAsync(id);
if(myObject==null)
{
返回HttpNotFound();
}
返回视图(myObject);
}
公共异步任务编辑([Bind(Include=“Id,aDefault,Name”)]MyObject-MyObject)
{
if(ModelState.IsValid)
{
myObject.dateModified=DateTime.Now;
db.Entry(myObject.State=EntityState.Modified;
wait db.saveChangesSync();//db是生成的dbcontext
返回操作(“索引”);
}
返回视图(myObject);
}
和(仅显示表单上的字段)视图:

@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@Html.HiddenFor(model => model.Id)

<div class="form-group">
    @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
        @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
    </div>
</div>


<div class="form-group">
    @Html.LabelFor(model => model.aDefault, htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        <div class="checkbox">
            @Html.EditorFor(model => model.aDefault)
            @Html.ValidationMessageFor(model => model.aDefault, "", new { @class = "text-danger" })
        </div>
    </div>
</div>
@Html.ValidationSummary(true,“,new{@class=“text danger”})
@Html.HiddenFor(model=>model.Id)
@LabelFor(model=>model.Name,htmlAttributes:new{@class=“controllabel col-md-2”})
@EditorFor(model=>model.Name,new{htmlAttributes=new{@class=“form control”})
@Html.ValidationMessageFor(model=>model.Name,“,new{@class=“text danger”})
@LabelFor(model=>model.aDefault,htmlAttributes:new{@class=“controllabel col-md-2”})
@EditorFor(model=>model.aDefault)
@Html.ValidationMessageFor(model=>model.aDefault,“,new{@class=“text danger”})
因此,当前,当我运行此代码并转到编辑区域时,我希望它获取名称和默认值,将它们发布到控制器,并使其仅修改数据库中的相关字段。但是,当前当我运行此代码时,我得到:

将datetime2数据类型转换为datetime数据类型导致值超出范围。 声明已终止

这使我相信dateCreated被设置为空。我确认了这一点,将其设置为可空,它不再抛出异常,但当然将数据库中的dateCreated设置为空


我是否需要像在隐藏字段中设置Id那样将所有属性绑定到视图?我希望不是因为我想我只需要绑定相关的项目。有什么方法可以排除这些一旦设置为不更新的字段吗?

感谢这些评论,以及过去24小时的一些研究,我意识到主要问题是实体框架为我生成的问题。这句话让我最头疼:

db.Entry(myObject).State = EntityState.Modified;
这将所有属性设置为modified,因此将所有属性的值都设置为null,而所有未绑定的属性都保持为null

我可以理解为什么另一个选项(也许更好的做法)可能是仅为视图中的必要属性添加另一个ViewModel,但我认为在这种情况下,控制器可能更适合实现正在发生的更改。以下是我修改后的post方法:

public async Task<ActionResult> Edit([Bind(Include = "Id,aDefault,Name")] MyObject myObject)
{
    if (ModelState.IsValid)
    {
        db.MyObjects.Attach(myObject); //MyObjects is the DbSet
        myObject.dateModified = DateTime.Now;
        db.Entry(myObject).Property(o => o.Name).IsModified = true;
        db.Entry(myObject).Property(o => o.aDefault)IsModified = true;
        await db.SaveChangesAsync(); //db is the generated dbcontext
        return RedirectToAction("Index");
    }
    return View(myObject);
}
公共异步任务编辑([Bind(Include=“Id,aDefault,Name”)]MyObject MyObject) { if(ModelState.IsValid) { db.MyObjects.Attach(myObject);//MyObjects是DbSet myObject.dateModified=DateTime.Now; db.Entry(myObject).Property(o=>o.Name).IsModified=true; db.Entry(myObject).Property(o=>o.aDefault)修改为true; wait db.saveChangesSync();//db是生成的dbcontext 返回操作(“索引”); } 返回视图(myObject); }
正确的方法是根据POST方法中的ID获取数据模型,然后更新相关属性。问题是框架无法区分缺失值和空值之间的差异。微软已经通过使用Delta来支持这一点:在JavaScript中,我们有未定义和null,这样我们就可以判断值是否丢失或为空,而在c#中只有null(我们无法判断我们是想用null值更新还是不想更新该字段)@StephenMuecke谢谢!因此,我认为您建议的方式是将模型作为参数传递,即编辑(MyObject模型)?实际上,我建议您使用仅包含3个属性(
Id
Name
aDefault
)的视图模型,并将其用作参数,而不使用
[Bind]
属性。(请注意,实际上并不需要隐藏输入,因为假设您使用默认路由,则其值将作为路由参数添加)