5

Spero che qualcuno possa aiutarmi. Sono nuovo di MVC, proveniente da winforms/console/vb6background.Oggetto figlio MVC Model null su post HTTP

Mi scuso se questo è già stato risolto, sto facendo fatica a capire come posso risolvere il problema di seguito.

ho un modello di vista:

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

sto pre-popolano l'oggetto figlio studente di questo ViewModel prima che si passi alla vista.

studente modello:

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

Il problema che ho è quando il modello viene restituito al metodo create HTTP post l'oggetto figlio studente è vuoto.

Il codice di controllo:

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

Vista Codice:

@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") 
} 

L'oggetto modello sulla vista è popolato con le informazioni studente. Quando questo viene passato a Crea controller POST, l'oggetto figlio studente è nullo!

Qualcuno può consigliare dove sto andando male o il modo corretto per raggiungere questo obiettivo?

La mia applicazione avrà molte forme che dovranno essere tutte pre-compilate con le informazioni degli studenti. Ogni studente avrà molte forme che dovranno essere compilate per loro.

Molte grazie in anticipo, Rob

risposta

6

Per ogni proprietà nel modello di dominio (nel tuo caso testvm) è necessario disporre di un elemento EditorFor o di ingresso (come TextBoxFor o così) sulla tua vista (o HiddenFor per ID o altri dati ui non utente). Può essere un modello annidato di binding dolore in MVC in quanto DefaultModelBinder potrebbe non essere in grado di legare l'intero oggetto. Tuttavia sarebbe un approccio più sicuro per esporre solo il proprietà richieste in vista come

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

e più tardi di controllo laterale

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

è possibile utilizzare automapper per questo scopo, come

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

si possono trovare ulteriori informazioni su Automapper su: https://github.com/AutoMapper/AutoMapper/wiki/Getting-started

5

tuo nome proprietà viene chiamata studentId (anche se di serie C# proprietà convenzione di denominazione impone che avrebbe dovuto essere chiamato StudentId):

public student studentID { get; set; } 

Ma nel tuo Bind sembra che tu abbia specificato alcune proprietà student che non esistono sul tuo modello di vista:

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

quindi probabilmente vuole sbarazzarsi di questo attributo Bind dalla tua azione di controllo:

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

Si noti inoltre che hai solo un campo nascosto per l'id studente all'interno del vostro modulo:

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

Non hai un campo nascosto corrispondente per la proprietà del nome dello studente, quindi non verrà mai postato all'azione del tuo controller.

1

L'attributo [Bind(Include = "id,date,student")] deve includere i nomi delle proprietà che si desidera impostare, student non è nel modello, ma è studentID, devono corrispondere.

Non è necessario specificare esplicitamente tutti i nomi dei campi che si desidera associare al modello, per impostazione predefinita verranno comunque associati a meno che non si comunichi al raccoglitore NOT di associarlo utilizzando [Bind(Exclude = "id,date,student")]. Pertanto, come al momento, raccomanderei di rimuovere l'attributo Include per facilitare la manutenzione a meno che non vi sia un motivo importante per utilizzarlo e semplicemente assicurare che i modelli che si associano includano solo i valori necessari.

In secondo luogo, è necessario assicurarsi che tutti i valori che si stanno postback da un modulo nello view abbiano gli stessi nomi di parametri e siano strutturati come quelli che si desidera associare al modello di richiesta.

questo:

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

non è la stessa:

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