我需要帮助做一些我认为很简单的事情。我正在使用ASP.net MVC 3和CodeFirst(CTP5)
我有两个实体:公司和位置。公司可以有很多地点。课程如下(删除所有不必要的信息)
public class Company
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
public virtual ICollection<Location> Locations { get; set; }
}
public class Location
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public virtual Company Company { get; set; }
}
现在在我的控制器中,我只允许在公司的上下文中创建位置,因此公司ID始终被传入(在视图中,我在只读字段中显示公司的名称,但不允许用户更改/编辑它。
public ActionResult Create(int companyId)
{
Company company = _session.Single<Company>(c => c.Id == companyId);
Location newLocation = new Location {Company = company};
return View(newLocation);
}
[HttpPost]
public ActionResult Create(Location location)
{
if (ModelState.IsValid)
{
_session.Add<Location>(location);
_session.CommitChanges();
return RedirectToAction("Index");
} else {
return View(location);
}
}
现在,每当我尝试创建新位置时,由于未提供location.Company.Name并且是公司上的必填字段,因此ModelState.IsValid始终为false。我从不试图在这里创建一家新公司,我只是想创建一个参考正确公司的位置。我不想将Name属性添加到视图中以使ModelState得到验证。如何轻松完成?我应该传递与观点不同的东西吗?还是对于观点?
答案 0 :(得分:2)
正如我在评论中所解释的那样,我偶然发现了一个小小的变化,这使得这项工作,仍然认为它是一个kludge,因为我不明白为什么我需要复制孩子Id参数,但我能做的最好/最简单的发现将来很容易更新,我将是第一个承认我不知道CodeFirst中所有(或大部分)内容的人。
我改变了位置类:
public class Location
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public virtual Company Company { get; set; }
}
要:
public class Location
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public int CompanyId { get; set; }
public virtual Company Company { get; set; }
}
据我所知,这根本没有改变数据库架构,但现在唯一需要的位置(验证时)是在CompanyId字段中有一个ID,公司属性可以保留为null(之前,它试图验证适当的公司,因为需要公司类)。
现在,在创建位置时,视图需要在CompanyId中传回的唯一内容。
有人看到任何缺点吗?还是更好的方式?
答案 1 :(得分:1)
您可以轻松地在form
上添加公司名称的隐藏字段。它的数据将被拾取并按预期发送到您的POST操作。
如果您根本不在服务器端使用公司名称,只要公司ID正确(因为您使用它),您就可以用任何虚拟文本填充此隐藏字段。但是,如果您的ID需要正确的公司名称,则必须将实际名称填入隐藏字段而不是虚拟文本。
反正。这将为您的公司名称添加隐藏字段
<%= Html.HiddenFor(m => m.Company.Name) %>
如果您没有将公司属性设置为任何内容,那么您也可以使用它:
<%= Html.Hidden("Company.Name", "Super duper company") %>
这个值是实际名称还是虚拟名称并不重要。您的模型将在回发时生效。
我想你使用的是常规回发而不是Ajax回发。如果你确实使用了Ajax,并且你正在使用jQuery并调用$.post()
或$.ajax()
或类似的东西,你可以随时提供你喜欢的任何对象。您可以在JavaScript代码中填写公司名称的任何值。
如果你在JavaScript中有复杂的对象,并希望将它们发送到具有强类型参数的控制器操作(因此它们将被验证),你可以使用我的this little jQuery plugin,这使得任何JSON对象都能正确准备发送到Asp.net MVC操作,因此数据将自动绑定到您的强类型数据以进行验证。 JavaScript的日期也是如此。 :)
由于您(在评论中)指出您的实体正在进行大量工作并且您可能正在添加/删除必填字段,因此更改所有相关视图可能非常繁琐。
然而,有很多方法可以让你的生活变得更容易,因为根据对象状态,可变模型和不同的验证方案:
为创建过程提供单独的视图模型,其中还包括自动转换为应用程序模型类的功能:
public class LocationCreate
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public int CompanyId { get; set; }
public Location ToModelInstance()
{
return new Location {
Id = this.Id,
Name = this.Name,
Company = new Company {
Id = this.CompanyId,
Name = "Super duper company Ltd." // you can as well omit this line
}
};
}
}
使用继承:
public class CompanyBase
{
public int Id { get; set; }
}
public class Company : CompanyBase
{
[Required]
public string Name { get; set; }
public virtual ICollection<Location> Locations { get; set; }
}
public class Location
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public virtual CompanyBase Company { get; set; }
}