5

Hoffe jemand kann mir helfen. Ich bin neu in MVC, komme aus einem winforms/console/vb6background.MVC Modell Kind Objekt null auf HTTP-Post

Entschuldigung, wenn dies bereits beantwortet wurde, bin ich schwer zu verstehen, wie ich das folgende Problem lösen kann.

Ich habe eine Ansicht Modell:

public class testvm 
{ 
    public int id { get; set; } 
    public DateTime date { get; set; } 
    public student studentID { get; set; } 

    public testvm() { } 

    public testvm (student s) 
    { 
     studentID = s; 
    } 
} 

Ich bin der Student Kind Ziel dieser Ansichtsmodell vorgebevölkern, bevor es zu der Ansicht geführt wird.

Studenten Modell:

public class student 
{ 
    [Key] 
    public int ID { get; set; } 
    public string Name { get; set; } 
} 

Das Problem, das ich habe, ist, wenn das Modell auf die HTTP-POST-Methode erstellen zurückgegeben wird der Student Kind-Objekt leer ist.

Der Controller-Code:

// GET: testvms/Create 
public ActionResult Create(int sId) 
{ 
    student a = db.students.Find(sId); 

    testvm b = new testvm(a); 

    return View(b); 
} 

[HttpPost] 
[ValidateAntiForgeryToken] 
public ActionResult Create([Bind(Include = "id,date,student")] testvm testvm) 
{ 
    if (ModelState.IsValid) 
    { 
     db.testvws.Add(testvm); 
     db.SaveChanges(); 
     return RedirectToAction("Index"); 
    } 

    return View(testvm); 
} 

anzeigen Code:

@model WebApplication2.Models.testvm 

@{ 
ViewBag.Title = "Create"; 
} 

<h2>Create</h2> 


@using (Html.BeginForm()) 
{ 
@Html.AntiForgeryToken() 

<div class="form-horizontal"> 
    <h4>testvm</h4> 
    <hr /> 


    @Html.HiddenFor(model => model.studentID.ID) 

    @Html.ValidationSummary(true, "", new { @class = "text-danger" }) 
    <div class="form-group"> 
     @Html.LabelFor(model => model.date, htmlAttributes: new { @class = "control-label col-md-2" }) 
     <div class="col-md-10"> 
      @Html.EditorFor(model => model.date, new { htmlAttributes = new { @class = "form-control" } }) 
      @Html.ValidationMessageFor(model => model.date, "", new { @class = "text-danger" }) 
     </div> 
    </div> 

    <div class="form-group"> 
     <div class="col-md-offset-2 col-md-10"> 
      <input type="submit" value="Create" class="btn btn-default" /> 
     </div> 
    </div> 
</div> 
} 

<div> 
@Html.ActionLink("Back to List", "Index") 
</div> 

@section Scripts { 
@Scripts.Render("~/bundles/jqueryval") 
} 

Das Model-Objekt auf der Ansicht ist, mit dem Schüler Informationen bevölkert. Wenn dies an den Create POST-Controller zurückgegeben wird, ist das Schüler-Child-Objekt null!

Kann jemand bitte beraten, wo ich falsch liege oder den richtigen Weg, dies zu erreichen?

Meine Anwendung wird viele Formen haben, die alle mit Studenteninformationen ausgefüllt werden müssen. Jeder Student wird viele Formulare haben, die für sie ausgefüllt werden müssen.

Vielen Dank im Voraus, Rob

Antwort

6

Für jede Eigenschaft in Domain-Modell (in Ihrem Fall testvm) Sie müssen ein EditorFor oder Eingangselement haben (wie TextBoxFor oder So) auf Ihre Sicht (oder HiddenFor für ID oder andere nicht Benutzer UI Daten) .Es kann eine verschachtelte verschachtelte Modelle in MVC sein, da die DefaultModelBinder möglicherweise nicht in der Lage, ganze Objekt zu binden.Es wäre jedoch sicherer Ansatz, nur die erforderliche Eigenschaften auf Ansicht wie

@Html.HiddenFor(model => model.studentID.ID) 
@Html.HiddenFor(model => model.studentID.Name) 

und später auf Controller-Seite

[HttpPost] 
[ValidateAntiForgeryToken] 
public ActionResult Create(testvm testvm) 
{ 
    var originalobj=db.get //get fresh copy from data store 
originalobj.Name=testvm.Name; 
//  ...other properties 
//perform required operations on originalobj 
} 

Sie AutoMapper für diesen Zweck als

Mapper.CreateMap<testvm,testvm>(); 
originalobj=Mapper.Map<testvm,testvm>(testvm,originalobj); 

verwenden können, können Sie mehr Informationen zu AutoMapper finden Sie unter: https://github.com/AutoMapper/AutoMapper/wiki/Getting-started

5

ist Ihr Eigenschaftsname studentId genannt (obwohl Standard C# Eigenschaft Namenskonvention schreibt vor, dass es StudentId genannt werden soll):

public student studentID { get; set; } 

Aber in Ihrem Bind Attribut Sie scheinen bestimmte student Eigenschaft angegeben haben, die nicht wirklich auf Ihrem Ansicht Modell existiert:

[Bind(Include = "id,date,student")] 

So möchten Sie wahrscheinlich dieses Bind Attribut aus der Controller-Aktion, um loszuwerden:

[HttpPost] 
[ValidateAntiForgeryToken] 
public ActionResult Create(testvm testvm) 
{ 
    ... 
} 

Beachten Sie auch, dass Sie nur ein verstecktes Feld für die Schüler-ID in Ihrer Form haben:

@Html.HiddenFor(model => model.studentID.ID) 

Sie verfügen nicht über ein entsprechendes ausgeblendetes Feld für die Eigenschaft des Schülernamens, so dass es nie wieder in Ihre Controller-Aktion zurückgeschrieben wird.

1

Ihr Attribut [Bind(Include = "id,date,student")] sollte die Namen der Eigenschaften enthalten, die Sie festlegen möchten, student ist nicht in Ihrem Modell, aber studentID ist, sie müssen übereinstimmen.

Sie müssen nicht alle Feldnamen explizit angeben, die an Ihr Modell gebunden werden sollen. Standardmäßig werden sie trotzdem gebunden, es sei denn, Sie weisen den Binder an, ihn nicht mit [Bind(Exclude = "id,date,student")] zu binden. Aus diesem Grund empfehle ich Ihnen, Ihr Include-Attribut zu entfernen, um die Wartung zu erleichtern, es sei denn, es gibt einen wichtigen Grund, es zu verwenden, und sicherzustellen, dass die verknüpften Modelle nur die Werte enthalten, die Sie benötigen.

Zweitens müssen Sie sicherstellen, dass alle Werte, die Sie aus einem Formular in Ihrem view zurückgeben, die gleichen Parameternamen haben und genauso strukturiert sind wie diejenigen, die an das Anfragemodell gebunden werden sollen.

Dieses:

@Html.HiddenFor(model => model.studentID.ID) 

Ist das nicht das gleiche wie:

@Html.HiddenFor(model => model.studentID) 
Verwandte Themen