简体   繁体   中英

Why nested objects in view are null when calling the view. ASP.Net MVC

I'm new to MVC and I'm struggling deeply with this behaviour:

When I want to save with the Edit method (POST) I make some validations and when an error occurs I call again the view and I send the same object. However in the view all the inner objects are null.

Here is an example:

public class Product 
{
  public int Id { get; set; }
  public string Name { get; set; }
  public DateTime ExpirationDate { get; set; }
  public int CategoryId { get; set; }
  public virtual Category Category { get; set; }
}

public class Category 
{
  public int CategoryId { get; set; }
  public string Name { get; set; }
}

My controller is this:

[HttpPost]
public ActionResult Edit(Product product, string submitButton)
{
  if(submitButton == "Save")
  {
    if (ModelState.IsValid)
    {
        db.Entry(product).State = EntityState.Modified;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
  }
  else // Validate
  {
    if(product.Expiration <= DateTime.Now)
    {
      ViewBag.Message "Product is expired";
      return View(product); // In the view the object property 'Category' is null. Why?
    }
  }
}

Update. Here's the view.

@model sgt.Models.Product

@{
    ViewBag.Title = "Edit Product";
}

<h2>Edit</h2>

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

    <div class="form-horizontal">
        <h4>Product</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        @Html.HiddenFor(model => model.Id)

        <div class="form-group">
            @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
                <input type="submit" value="Validate" class="btn btn-default" />
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.ExpirationDate, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.ExpirationDate, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.ExpirationDate, "", new { @class = "text-danger" })
                <input type="submit" value="Validate" class="btn btn-default" />
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Category, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DisplayFor(model => model.Category.Name, new { htmlAttributes = new { @class = "form-control" } })
            </div>
        </div>

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

<div>
    @Html.ActionLink("Return", "Index")
</div>

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

Thanks in advance

YOu have a logical Error in your code.

You are not returning the View if (ModelState.IsValid) Fails

[HttpPost]
public ActionResult Edit(Product product, string submitButton)
{
    if(submitButton == "Save")
    {
        if (ModelState.IsValid)
        {
            db.Entry(product).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        // Here RETURN VIEW and MODEL

        return View(product);
    }
    else // Validate
    {
        if(product.Expiration <= DateTime.Now)
        {
        ViewBag.Message "Product is expired";
        return View(product); // In the view the object property 'Category' is null. Why?
        }

        // ALSO HERE YOU ARE NOT RETURNING A VIEW AND MODEL

        return View(product);
    }
}

Just wondering, but I think you want to check if Model is Valid AND product.Expiration <= DateTime.Now

[HttpPost]
public ActionResult Edit(Product product, string submitButton)
{
      if(product.Expiration <= DateTime.Now && submitButton != "Save"){
         ModelState.AddModelError("Expiration", "Product is expired");
       }


       if (ModelState.IsValid)
       {
           db.Entry(product).State = EntityState.Modified;
           db.SaveChanges();
           return RedirectToAction("Index");
        }
        return View(product);
}

EDIT: TRY THIS:

   [HttpPost]
   public ActionResult Edit(Product product, string submitButton)
   {
    if(submitButton == "Save")
    {
            if (ModelState.IsValid)
            {
                db.Entry(product).State = EntityState.Modified;
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(product);
    }
       if(product.Expiration <= DateTime.Now)
       {
           ViewBag.Message "Product is expired";
       }
       return View(product);
   }

EDIT YOUR VIEW:

<div class="form-group">
    @Html.HiddenFor(m => m.Category.CategoryId)
    @Html.HiddenFor(m => m.Category.Name )

    @Html.LabelFor(model => model.Category, htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.DisplayFor(model => model.Category.Name, new { htmlAttributes = new { @class = "form-control" } })
    </div>
</div>      

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM