5

Mam nadzieję, że ktoś może mi pomóc. Jestem nowy w MVC, pochodzącym z winforms/console/vb6background.Obiekt potomny modelu MVC null na poście HTTP

Przepraszam, jeśli już udzielono odpowiedzi, staram się zrozumieć, w jaki sposób mogę rozwiązać poniższy problem.

Mam modelu wyświetlania:

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

Ja wstępnie wypełniania studenta podrzędny obiekt tego ViewModel zanim zostanie przekazany do widzenia.

Student Model:

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

Mam problem jest, gdy model jest zwracana do stworzenia metody HTTP POST przedmiot uczeń dziecko jest pusty.

Kod kontroler:

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

Zobacz Kod:

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

Model obiektów na widoku jest wypełniane informacjami studentów. Kiedy zostanie on przekazany do kontrolera Create POST, obiekt potomny ucznia ma wartość NULL!

Czy ktoś może doradzić, gdzie idę źle lub w prawidłowy sposób, aby to osiągnąć?

Moja aplikacja będzie zawierała wiele formularzy, które będą wstępnie wypełnione informacjami o uczniach. Każdy uczeń będzie miał wiele formularzy, które będą musiały zostać wypełnione.

Dziękujemy wcześniej, Rob

Odpowiedz

6

dla każdej nieruchomości w modelu domeny (w przypadku testvm) musi mieć element EditorFor lub wejście (jak TextBoxFor lub tak) na twoim widoku (lub HiddenFor dla ID lub innych danych użytkownika spoza użytkownika). Może to być model zagnieżdżony wiążący ból w MVC, ponieważ DefaultModelBinder może nie być w stanie powiązać całego obiektu.Jednakże bezpieczniejsze byłoby odsłonięcie tylko wymagane właściwości w widoku, takie jak

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

a później Controller Side

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

można użyć AutoMapper w tym celu jako

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

można znaleźć więcej informacji o Automapper na: https://github.com/AutoMapper/AutoMapper/wiki/Getting-started

5

Imię właściwość nazywa studentId (choć standard C# właściwość konwencji nazewnictwa podpowiada, że ​​powinien on być nazywany StudentId):

public student studentID { get; set; } 

ale w twoim Bind atrybut wydaje się mieć określone pewne właściwości student, które tak naprawdę nie istnieją w twoim modelu widoku:

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

Więc prawdopodobnie chcesz, aby pozbyć się tego atrybutu Bind z działania kontrolera:

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

Należy również pamiętać, że masz tylko ukryte pole dla identyfikatora studenta wewnątrz swojej postaci:

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

Nie masz odpowiedniego ukrytego pola dla właściwości nazwy ucznia, więc nigdy nie zostanie przesłane z powrotem do działania kontrolera.

1

Twój atrybut powinien zawierać nazwy właściwości, które chcesz ustawić, student nie jest w twoim modelu, ale studentID jest, muszą pasować.

Nie musisz wyraźnie określać wszystkich nazw pól, które chcesz powiązać z modelem, domyślnie będą one związane, chyba że wskażesz element wiążący, aby go nie wiązał, używając [Bind(Exclude = "id,date,student")]. Dlatego w obecnym stanie zalecam usunięcie atrybutu Include, aby ułatwić konserwację, chyba że istnieje ważny powód, aby go użyć i po prostu upewnić się, że modele, które łączą się, zawierają tylko te wartości, których potrzebujesz.

Po drugie, musisz upewnić się, że wszelkie wartości, które publikujesz z formularza w twoim view, mają te same nazwy parametrów i mają taką samą strukturę jak te, które chcesz powiązać z modelem żądania.

to:

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

nie jest takie samo jak:

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