MVC4:在创建新记录时,Modelstate无效。

时间:2021-10-12 02:42:33

I try to add a new Country which has a link to continent. When I press the "Create" button, it doesn't add a new record. I debugged my project and I think it's because the ValidState is false. The reason because of this is that the property "Continent" is null, but the Continent_Id isn't. I have the same problem when I try to edit an existing Country. (I have populated my database with an SQL script in SQL Management Studio)

我试图添加一个与大陆有联系的新国家。当我按下“创建”按钮时,它不会添加新的记录。我调试了我的项目,我认为这是因为ValidState是假的。因为这个原因,属性“大洲”是null,而Continent_Id不是。当我试图编辑一个现有的国家时,我也有同样的问题。(我在SQL Management Studio中使用SQL脚本填充我的数据库)

Can someone help me please?

谁能帮帮我吗?

Continent class:

大陆类:

public class Continent
{
    public int Id { get; set; }
    [Required, MaxLength(25)]
    public string Name { get; set; }

    //Navigation
    public virtual List<Country> Countries { get; set; }
}

Country class

国家类

public class Country
{
    public int Id { get; set; }
    [Required, MaxLength(25)]
    public string Name { get; set; }
    [MaxLength(5)]
    public string Abbreviation { get; set; }

    public int Continent_Id { get; set; }

    //Navigation
    [Required, ForeignKey("Continent_Id")]
    public virtual Continent Continent { get; set; }

}

Controller class ( create function )

控制器类(创建函数)

  //
    // GET: /Countries/Create

    public ActionResult Create()
    {
        ViewBag.Continent_Id = new SelectList(db.Continents, "Id", "Name");
        return View();
    }

    //
    // POST: /Countries/Create

    [HttpPost]
    public ActionResult Create(Country country)
    {
       var errors = ModelState.Values.SelectMany(v => v.Errors); //to check the errors
        if (ModelState.IsValid)
        {
            db.Countries.Add(country);
            db.SaveChanges();
            return RedirectToAction("Index");
        }


        ViewBag.Continent_Id = new SelectList(db.Continents, "Id", "Name", country.Continent_Id);
        return View(country);

4 个解决方案

#1


3  

Just before the line if (ModelState.IsValid) put this ModelState.Remove("v_id"); Where v_id is your primarykey column name in your case

如果(ModelState.IsValid)使用该模型,请删除(“v_id”);在您的案例中,v_id是您的主键列名?

#2


0  

I'm not sure, but I believe your issue is timing. Model validation happens automatically during binding; at that time, the Continent property is null. You set the property later but the model state is not re-evaluated when you check IsValid. I see three options:

我不确定,但我相信你的问题在于时机。模型验证在绑定过程中自动发生;当时,大陆属性为空。稍后您将设置属性,但是在检查是否有效时不会重新评估模型状态。我看到三个选项:

  • Quick and dirty: Take the Required validation off of Continent and validate Continent_Id instead, adding a check in the controller to ensure a valid Continent is retrieved from Find().
  • 快速而又脏:将必需的验证从大洲中取出并验证Continent_Id,在控制器中添加一个检查,以确保从Find()检索到一个有效的洲。
  • Most work: Create a custom model binder to actually use the Continent_Id to retrieve and populate the Continent. You are almost there on this one since having both Continent_Id and Continent as properties of Country is redundant and an opportunity for inconsistencies.
  • 大多数工作:创建一个自定义模型绑定器来实际使用Continent_Id来检索和填充该大陆。由于有Continent_Id和Continent作为国家属性是冗余的,并且存在不一致的机会,所以您几乎是在这个问题上。
  • Probably best option: Make your controller accept a view model that only has the data you expect to come back from the form and populate a Country object from it.
  • 可能是最好的选择:让您的控制器接受一个视图模型,该模型只包含您希望从表单返回的数据,并从表单中填充一个Country对象。

#3


0  

I fixed this issue by putting the Required validation off of Continent, and set it only at the Continent_Id. Now the ID property is required, but the Continent isn't.

通过将必需的验证从大洲上移除,并将其设置为Continent_Id,我修复了这个问题。现在需要ID属性,但大陆不需要。

public class Country
{
public int Id { get; set; }
[Required, MaxLength(25)]
public string Name { get; set; }
[MaxLength(5)]
public string Abbreviation { get; set; }

[Required] //added Required
public int Continent_Id { get; set; }

//Navigation
[ForeignKey("Continent_Id")] //removed Required
public virtual Continent Continent { get; set; }

}

Thanks for the responses !

谢谢你的回复!

#4


-1  

The reason the ModelState isn't valid is because you have marked the Continent property as required but in i guess in your view you don't have form fields the will bind to some properties of the Continent object.

ModelState无效的原因是您已经按照要求标记了大洲属性,但是在您的观点中,我猜您没有表单字段,它将绑定到洲对象的某些属性。

So either don't mark the Continent object as required or provide a hidden field with a name of Continent.Id or Continent.Name so that the model binder will populate the Continent property:

因此,要么不按要求标记大洲对象,要么提供一个带有大洲名称的隐藏字段。Id或大陆。名称以便模型绑定器将填充大洲属性:

@Html.HiddenFor(m => m.Continent.Id)

But that will lead to the next problem: You habe marked the Name property of the Continent class as required so you will have to provide a form field for that property too.

但这将导致下一个问题:您必须按要求标记大洲类的Name属性,因此您必须为该属性提供一个表单字段。

The base problem is, that you try to reuse your repository classes as viewmodel classes. A better approach would be to use separate classes as viewmodels to pass your data between the controller and the view:

基本问题是,您试图将存储库类重用为viewmodel类。更好的方法是使用单独的类作为视图模型,在控制器和视图之间传递数据:

class CountryViewModel {
    public int Id { get; set; }
    [Required, MaxLength(25)]
    public string Name { get; set; }
    [MaxLength(5)]
    public string Abbreviation { get; set; }

    public int Continent_Id { get; set; }
}

To map between your Country and CountryViewModel object use a mapper like AutoMapper.

要在您的国家和乡村视图模型对象之间进行映射,请使用类似AutoMapper的映射器。

#1


3  

Just before the line if (ModelState.IsValid) put this ModelState.Remove("v_id"); Where v_id is your primarykey column name in your case

如果(ModelState.IsValid)使用该模型,请删除(“v_id”);在您的案例中,v_id是您的主键列名?

#2


0  

I'm not sure, but I believe your issue is timing. Model validation happens automatically during binding; at that time, the Continent property is null. You set the property later but the model state is not re-evaluated when you check IsValid. I see three options:

我不确定,但我相信你的问题在于时机。模型验证在绑定过程中自动发生;当时,大陆属性为空。稍后您将设置属性,但是在检查是否有效时不会重新评估模型状态。我看到三个选项:

  • Quick and dirty: Take the Required validation off of Continent and validate Continent_Id instead, adding a check in the controller to ensure a valid Continent is retrieved from Find().
  • 快速而又脏:将必需的验证从大洲中取出并验证Continent_Id,在控制器中添加一个检查,以确保从Find()检索到一个有效的洲。
  • Most work: Create a custom model binder to actually use the Continent_Id to retrieve and populate the Continent. You are almost there on this one since having both Continent_Id and Continent as properties of Country is redundant and an opportunity for inconsistencies.
  • 大多数工作:创建一个自定义模型绑定器来实际使用Continent_Id来检索和填充该大陆。由于有Continent_Id和Continent作为国家属性是冗余的,并且存在不一致的机会,所以您几乎是在这个问题上。
  • Probably best option: Make your controller accept a view model that only has the data you expect to come back from the form and populate a Country object from it.
  • 可能是最好的选择:让您的控制器接受一个视图模型,该模型只包含您希望从表单返回的数据,并从表单中填充一个Country对象。

#3


0  

I fixed this issue by putting the Required validation off of Continent, and set it only at the Continent_Id. Now the ID property is required, but the Continent isn't.

通过将必需的验证从大洲上移除,并将其设置为Continent_Id,我修复了这个问题。现在需要ID属性,但大陆不需要。

public class Country
{
public int Id { get; set; }
[Required, MaxLength(25)]
public string Name { get; set; }
[MaxLength(5)]
public string Abbreviation { get; set; }

[Required] //added Required
public int Continent_Id { get; set; }

//Navigation
[ForeignKey("Continent_Id")] //removed Required
public virtual Continent Continent { get; set; }

}

Thanks for the responses !

谢谢你的回复!

#4


-1  

The reason the ModelState isn't valid is because you have marked the Continent property as required but in i guess in your view you don't have form fields the will bind to some properties of the Continent object.

ModelState无效的原因是您已经按照要求标记了大洲属性,但是在您的观点中,我猜您没有表单字段,它将绑定到洲对象的某些属性。

So either don't mark the Continent object as required or provide a hidden field with a name of Continent.Id or Continent.Name so that the model binder will populate the Continent property:

因此,要么不按要求标记大洲对象,要么提供一个带有大洲名称的隐藏字段。Id或大陆。名称以便模型绑定器将填充大洲属性:

@Html.HiddenFor(m => m.Continent.Id)

But that will lead to the next problem: You habe marked the Name property of the Continent class as required so you will have to provide a form field for that property too.

但这将导致下一个问题:您必须按要求标记大洲类的Name属性,因此您必须为该属性提供一个表单字段。

The base problem is, that you try to reuse your repository classes as viewmodel classes. A better approach would be to use separate classes as viewmodels to pass your data between the controller and the view:

基本问题是,您试图将存储库类重用为viewmodel类。更好的方法是使用单独的类作为视图模型,在控制器和视图之间传递数据:

class CountryViewModel {
    public int Id { get; set; }
    [Required, MaxLength(25)]
    public string Name { get; set; }
    [MaxLength(5)]
    public string Abbreviation { get; set; }

    public int Continent_Id { get; set; }
}

To map between your Country and CountryViewModel object use a mapper like AutoMapper.

要在您的国家和乡村视图模型对象之间进行映射,请使用类似AutoMapper的映射器。