2

我需要一些帮助来做一些我认为很简单的事情。我正在使用带有 CodeFirst (CTP5) 的 ASP.net MVC 3

我有两个实体:公司和位置。一家公司可以有很多地点。课程如下(去除所有不必要的信息)

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);
        }
    }

现在,每当我尝试创建新位置时,ModelState.IsValid 始终为 false,因为未提供 location.Company.Name 并且是 Company 的必填字段。我从不尝试在这里创建一家新公司,我只是尝试创建一个引用正确公司的位置。我不想将 Name 属性添加到视图中只是为了让 ModelState 进行验证。这怎么能轻松完成?我应该传递与视图不同的东西吗?或视图?

4

2 回答 2

2

As i was explaining in my comment, i stumbled upon a small change which makes this work, still think it is a kludge as I dont see why i need to duplicate the child Id paramater, but the best/simplest one I could find that should be easy to update in the future and I will be the first to admit I dont know all (or most) of what there is in CodeFirst.

I changed the location class from:

public class Location  
{      
    public int Id { get; set; }        

    [Required]      
    public string Name { get; set; }        

    [Required]      
    public virtual Company Company { get; set; }    
}

To:

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; }    
}

Now as far as I can tell, this hasnt changed the database schema at all, but now the only thing which is required on the Location (when validating) is that there is an ID in the CompanyId field, the Company property can be left null (before, it was trying to validate a proper Company since the Company class was required).

So now when creating a Location, the only thing the view needs to pass back in the CompanyId.

Anyone see any drawbacks? or a better way?

于 2011-02-15T21:54:09.577 回答
1

您可以轻松地您的form. 它的数据将按预期被拾取并发送到您的 POST 操作。

如果您根本不在服务器端使用公司名称,只要公司 ID 正确(因为您使用它),您可以使用任何虚拟文本填充此隐藏字段。但是,如果您确实需要正确的公司名称和您的 ID,则必须将实际名称填写到隐藏字段中,而不是一些虚拟文本。

反正。这将为您的公司名称添加一个隐藏字段

<%= Html.HiddenFor(m => m.Company.Name) %>

如果您没有将 Company 属性设置为任何内容,那么您也可以使用它:

<%= Html.Hidden("Company.Name", "Super duper company") %>

这个值是实际名称还是虚拟名称并不重要。您的模型将在回发时有效。

定期回发还是 Ajax?

我想您使用的是常规回发而不是 Ajax 回发。如果您确实使用 Ajax 并且您正在使用 jQuery 和调用$.post()$.ajax()类似的东西,您总是可以提供您喜欢的任何对象。您可以在 JavaScript 代码中填写公司名称的任何值。

如果您在 JavaScript 中有复杂的对象,并希望将它们发送到具有强类型参数的控制器操作(因此它们将被验证),您可以使用我的这个小 jQuery 插件,它准备任何 JSON 对象以正确发送到 Asp。 net MVC 操作,因此数据将自动绑定到您的强类型以进行验证。JavaScript 日期也是如此。:)

附加信息

由于您(在评论中)指出您的实体正在进行大量工作并且您可能正在添加/删除必填字段,因此更改所有相关视图可能非常繁琐。

然而,当涉及到可变模型和取决于对象状态的不同验证场景时,您可以采取一些方法让您的生活更轻松:

  1. 具有用于创建过程的单独视图模型,其中还包括自动转换为应用程序模型类的功能:

    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
                }
            };
        }
    }
    
  2. 使用继承:

    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; }
    
    }
    
于 2011-02-15T02:49:22.870 回答