Обновление данных Master-Detail / Parent-Child в MVC - PullRequest
0 голосов
/ 27 апреля 2018

Иметь представление с представлением стиля основной детали для счета. Мастер - это счет, детали - это строки счета. Я пытаюсь получить подробные элементы данных для сохранения при редактировании сообщения, но подробные данные теряются при достижении сообщения Редактировать на контроллере. Таким образом, основные данные сохраняются нормально, но детали, очевидно, не сохраняются.

Класс счета-фактуры:

public class Invoice
{
    public Invoice()
    {

    }

    [Required]
    [Key]
    public int InvoiceID { get; set; }

    [Required]
    [StringLength(30)]
    [DisplayName("Invoice Number")]
    public string InvoiceNumber { get; set; }

    [Required, DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    [DataType(DataType.Date)]
    [Column(TypeName = "Date")]

    [DisplayName("Invoice Date")]
    public DateTime InvoiceDate { get; set; }

    public List<InvoiceLine> InvoiceLines { get; set; }

    [ForeignKey("Client")]
    public int OwnerClientIDFK { get; set; }

    [DisplayName("Client")]
    public Client Client { get; set; }
}

Класс строки счета:

public class InvoiceLine
{
    public InvoiceLine()
    {

    }

    [Key]
    [Required]
    public int InvoiceLineId { get; set; }

    [Required]
    [StringLength(255)]
    [DisplayName("Item")]
    public string ItemName { get; set; }

    [DisplayName("Description")]
    public string ItemDescription { get; set; }

    [Required]
    public int Quantity { get; set; }

    [Required]
    [DisplayFormat(DataFormatString = "{0:C}", ApplyFormatInEditMode = true)]
    public decimal Value { get; set; }

    [ForeignKey("ParentInvoice")]
    public int InvoiceID { get; set; }

    public Invoice ParentInvoice { get; set; }

} 

Контроллер Редактировать (получить):

    public ActionResult Edit(int? id)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        // Invoice invoice = db.Invoices.Find(id);
        Invoice invoice = db.Invoices.Include(i => i.InvoiceLines)
                            .Include(i => i.Client)
                            .Where(c => c.InvoiceID == id).FirstOrDefault();

        if (invoice == null)
        {
            return HttpNotFound();
        }
        ViewBag.OwnerClientIDFK = new SelectList(db.Clients, "ClientId", "CompanyName", invoice.OwnerClientIDFK);
        return View(invoice);
    } 

Редактор контроллера (сообщение):

    public ActionResult Edit([Bind(Include = "InvoiceID,InvoiceNumber,InvoiceDate,OwnerClientIDFK")] Invoice invoice)
    {
        if (ModelState.IsValid)
        {
            db.Entry(invoice).State = EntityState.Modified;

            foreach (var invLine in invoice.InvoiceLines)
            {
                db.Entry(invLine).State = EntityState.Modified;
            }

            db.SaveChanges();
            return RedirectToAction("Index");
        }
        ViewBag.OwnerClientIDFK = new SelectList(db.Clients, "ClientId", "CompanyName", invoice.OwnerClientIDFK);
        return View(invoice);
    } 

Так что в приведенном выше примере, когда он достигает foreach, он генерирует исключение, потому что InvoiceLines имеет значение null.

Просмотр:

@model DemoApp.Entities.Invoice

@{
    ViewBag.Title = "Edit";
}

<h2>Edit</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()

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

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

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

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

    <div class="form-group">
        <h2>Invoice Lines</h2>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })

        <div class="row">
            <div class="col-md-8">
                <table class="table">
                    <thead>
                        <tr>
                            <th>Item</th>
                            <th>Description</th>
                            <th>Qty</th>
                            <th>Unit Value</th>
                        </tr>
                    </thead>
                    <tbody>
                        @for (int i = 0; i < Model.InvoiceLines.Count; i++)
                        {
                            <tr>
                                <td>@Html.EditorFor(x => x.InvoiceLines[i].ItemName, new { htmlAttributes = new { @class = "form-control" } })</td>
                            </tr>
                        }
                    </tbody>

                </table>
            </div>
        </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("Back to List", "Index")
</div>

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

Как мне получить его для обновления детальных / дочерних данных?

Любая помощь приветствуется. Заранее спасибо.

Ответы [ 3 ]

0 голосов
/ 30 апреля 2018

Что вам, вероятно, нужно, это загрузить строки счетов-фактур, когда вы получите родительский объект.

db.Entry (invoice) .Collection (i => i.InvoiceLines) .Load () должен сделать это.

0 голосов
/ 01 мая 2018

Во-первых, это довольно сложный сценарий. Есть много движущихся частей. Я действительно заинтересовался этим и написал пример приложения. :)

Вот ссылка на репозиторий на GitHub: https://github.com/benday/asp-mvc-invoice-sample

Есть несколько вещей, которые сговариваются, чтобы вызвать проблемы в вашем коде.

1) по иронии судьбы, Bind [], который у вас есть в вашем методе Edit (модель счета), мешает вам. Если вы удалите его полностью, ASP MVC попытается связать все. Прямо сейчас, это только связывает то, что вы говорите, чтобы связать, и так как вы не включаете коллекцию InvoiceLines, то она становится нулевой.

2) если вы хотите, чтобы ASP MVC пытался связать данные в вашей модели, вам нужно отправить эти данные обратно на сервер. Если эти строки счета-фактуры не представлены в HTML-форме и не представлены в виде полей формы, то эти данные просто будут отсутствовать.

В коде, который вы должны нарисовать в строках счета-фактуры, отсутствует большинство полей, необходимых для заполнения объектов InvoiceLine.

@Html.EditorFor (x => x.InvoiceLines [i] .ItemName, new { htmlAttributes = new {@class = "form-control"}})

Шаблон редактора для класса InvoiceLine

В моем примере кода я создал шаблон редактора для класса InvoiceLine. Это позволяет мне легко создавать привязываемый HTML для InvoiceLines, вызывая @Html.EditorFor(model => model.Invoice.InvoiceLines) asdf

Я знаю, что это не самый простой ответ, но я надеюсь, что это поможет вам преодолеть горб.

0 голосов
/ 30 апреля 2018

Вы не связываете InvoiceLines при редактировании метода действия после публикации

public ActionResult Edit ([Bind (Include = "InvoiceID, InvoiceNumber, InvoiceDate, OwnerClientIDFK, InvoiceLines")] Счет-фактура счета-фактуры) {

...