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的映射器。