我的视图模型是否太复杂"复杂"允许绑定帖子?

时间:2014-04-08 16:09:04

标签: c# asp.net-mvc asp.net-mvc-5

使用我的模型显示页面工作正常,但帖子不返回绑定模型。 我的课程:

public class ContactManager
{       
    public Contact Contact { get; set; }       
    public SelectList SalutationList { get; set; }
}
public class Contact
{
    public int Id{get;set;}
    public string FirstName{get; set;}
    public SalutationType SalutationType{get; set;}
}
 public class SalutationType
{      
    public int Id { get; set; }
    public string Name { get; set; }      
}

我的观点:

@model ViewModels.ContactManager

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)
    @Html.HiddenFor(model => model.Contact.Id)
    @Html.DropDownListFor(model => model.Contact.SalutationType.Id, Model.SalutationList)
    @Html.EditorFor(model => model.Contact.FirstName)
    <input type="submit" value="Save" />
}

问题似乎出现在DropDownListFor中。下拉列表正确显示正确的值,但是当我发布此页面时,完整的模型为空白。如果我像这样简化DropDownListFor,则按预期发布值。

@html.DroDownListFor(model=>model.MyPlaceHolderProp, Model.SalutationList)

我的模型太复杂了吗?我没有正确地做某事吗?

模型基于我在单独项目中创建的使用EF的几个表。我试图避免创建更多的类/模型然后我必须。

4 个答案:

答案 0 :(得分:1)

你也应该发布你的控制器动作,因为你的模型作为空白回来真的与此无关。以这种或那种方式更改DropDownListFor定义不应影响任何其他值的发布。

那就是说,你最终会遇到另一个问题,所以无论如何你需要重新组合。您不能仅回发相关项的ID值。实体框架会抱怨已经存在具有该ID的对象,或者更糟糕的是,如果该对象附加,它将使用该Name的新发布值更新具有该ID的行,在这种情况下什么都不是,所以它只是清除它。

当您使用单个项目(基本上是外键)创建关系时,如果您未指定用于保存该外键值的属性,则Entity Framework会在幕后为您创建一个跟踪关系的属性。在这种情况下,这意味着您的Contacts表中有一个名为SalutationType_Id的列。但是,您的班级无法直接访问此值。这就是为什么我建议你总是提供一个显式属性来处理这种关系:

[ForeignKey("SalutationType")]
public int SalutationTypeId { get; set; }

public SalutationType SalutationType { get; set; }

如果你这样做,那么你可以直接填充发布的id 那里,实体框架将创建关系。

@Html.DropDownListFor(m => m.Contact.SalutationTypeId, Model.SalutationList);

如果您坚持隐含密钥,那么您必须自己创建关系,方法是在视图模型上创建一个字段以保存已发布的值,然后使用该值从中查找SalutationType实例数据库,然后最后将其添加到Contact实例。

添加到您的视图模型

public int SalutationTypeId { get; set; }

在您的视图中

@Html.DropDownListFor(m => m.SalutationTypeId, Model.SalutationList)

在您的POST操作中

var salutationType = db.SalutationTypes.Find(model.SalutationTypeId);
contact.SalutationType = salutationType;

答案 1 :(得分:0)

你可以这样做。这可能是处理它的更“MVC最佳实践”方式。一切都在他们的模型中保持整洁,不需要手动ID。这些视图旨在表示它们所基于的底层模型。如果要创建具有表单的视图,请创建表示表单的模型并在视图中使用它。

修改您的模型,如:

public class PostModel
{
    public int ContactID { get; set; }
    public int SalutationID { get;  set; }
    public string FirstName { get; set; }
}

public class PostView
{
    public ContactManager contact { get; set; }
    public PostModel post { get; set; }
}

然后在控制器中创建PostView

public ActionResult Index() 
{
    //create the PostView model

    var pv = new PostView();
    pv.ContactManager = contactManager;
    pv.post = new PostView()
    {
        ContactID = contactManager.Contact.Id,
        SalutationID = contactManager.SalutationType.Id,
        FirstName = contactManager.Contact.FirstName
    };

    return View(pv);
}

然后视图可能像:

@model ViewModels.PostView

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)
    @Html.HiddenFor(model => model.post.ContactID)
    @Html.DropDownListFor(model => model.post.SalutationID, model.contact.SalutationList)
    @Html.EditorFor(model => model.post.FirstName)
    <input type="submit" value="Save" />
}

然后控制器中的post动作:

[HttpPost]
public ActionResult Index(PostView pv) 
{
    //post code
    //the posted data will be in pv.post
}

答案 2 :(得分:0)

您是否考虑过使用自定义模型绑定器?自定义模型绑定对于仍然相对简单的模型来说并不复杂,您可以根据需要处理序列化/反序列化。

http://msdn.microsoft.com/en-us/magazine/hh781022.aspx

http://ivonna.biz/blog/2012/2/2/custom-aspnet-model-binders-series,-part-3-subclassing-your-models.aspx

http://forums.asp.net/t/1944696.aspx?what+is+custom+model+binding+in+mvc

答案 3 :(得分:0)

我不确定这会对你有什么帮助...我有一个类似的问题,但我使用ajax回发...无论如何,我忘了用[Serializable]属性标记我的绑定类。

所以你可以试试

[Serializable]
public class Contract {
  ...
}

同样,我正在使用Json回发给我的控制器,所以可能没有相关或帮助你。但是,我觉得值得一试。