Update database from View in MVC asp.net Core 2.0

0

I hope to express myself clearly and be able to get some help.

I'm stuck with updating some fields in my database table from the View. Currently I could make it work but only update the data of the first result.

How should it work? Payment orders are entered into to customers that are paying off a debt. Filter the table to show the payment orders that were entered in the month and I have to update the fields of FechaLiq (datetime) and Liquidada (bool) .

Use VS 2017 and asp.net Core 2.0.

I read in several posts that the problem comes from using foreach but I did not know how to adapt my code to what they say here

I leave parts of the code.

Driver

[HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> LiquidaOpj(int? NroOrden)
    {
        if (NroOrden == null)
        {
            return NotFound();
        }

        var opjToUpdate = await _context.Opj.SingleOrDefaultAsync(o => o.NroOrden == NroOrden);

        if (await TryUpdateModelAsync<Opj>(
            opjToUpdate,
            "",
            o => o.NroOrden,
            o => o.Liquidada,
            o => o.FechaLiq))
        {
            try
            {
                await _context.SaveChangesAsync();
                return View("Success");
            }
            catch (DbUpdateException)
            {
                //Log the error (uncomment ex variable name and write a log.
                ModelState.AddModelError("", "Fallo al guardar los cambios. " +
                    "Intente nuevamente, si el error sigue " +
                    "comuníquese con el administrador.");
            }
            return RedirectToAction(nameof(Index));
        }
        return View(opjToUpdate);
    }

View (first the search form)

<div class="col-md-6">
    <h4>Busqueda</h4>
    <hr />
    <form method="get">
        <div class="form-group">
            <label>Fecha Desde:</label>
            <input class="form-control input-sm" name="desde" type="date" />
        </div>
        <div class="form-group">
            <label>Fecha Hasta:</label>
            <input class="form-control input-sm" name="hasta" type="date" />
        </div>
        <input type="submit" asp-action="Index" class="btn btn-info btn-sm" value="Buscar" />
    </form>                
</div>

(form to show results with the submit)

 <form asp-action="LiquidaOpj">
        <table class="table">
            <thead>
                <tr>
                    <th>
                        @Html.DisplayNameFor(model => model.Presentacion)
                    </th>
                    <th>
                        @Html.DisplayNameFor(model => model.NroOrden)
                    </th>
                    <th>
                        @Html.DisplayNameFor(model => model.Caratula)
                    </th>
                    <th>
                        @Html.DisplayNameFor(model => model.DNI)
                    </th>
                    <th>
                        @Html.DisplayNameFor(model => model.Liquidada)
                    </th>
                    <th></th>
                </tr>
            </thead>
            <tbody>

                @foreach (var item in Model)
                {
                    <tr>
                        <td>
                            @Html.DisplayFor(modelItem => item.Presentacion)
                            <input name="FechaLiq" type="hidden" value="@item.Presentacion" />
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.NroOrden)
                            <input name="NroOrden" type="hidden" value="@item.NroOrden" />
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.Caratula)
                            <input name="Caratula" type="hidden" value="@item.Caratula" />
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.DNI)
                            <input name="Dni" type="hidden" value="@item.DNI" />
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.Liquidada)
                            <input name="Liquidada" type="hidden" value="true" style="display:none" checked="checked">
                        </td>
                        <td>
                            <a asp-action="Details" asp-controller="Opjs" asp-route-id="@item.NroOrden">Detalle</a>
                        </td>
                    </tr>
                }
            </tbody>
        </table>
        <div class="form-group">
            <input type="submit" class="btn btn-success btn-sm" value="Generar" />
        </div>
    </form>

As you will see add <input type="hidden"/> to send the controller the data to update.

Any help will be welcome.

Thank you very much for reading.

    
asked by German W 15.02.2018 в 22:40
source

2 answers

0

@Xique I could do it. I made changes in the View and also in the controller. I publish for whoever has a similar situation or my answer serves as an example:

In the View add:

@for (int i = 0; i < Model.Count; i++)
   { 
     <td>@Html.HiddenFor(model => model[i].NroOrden)</td>
   }

This is added so that a name of different NroOrden passes for each of the results. According to the comment of the post

  

Your first problem is that you use a foreach loop is generating duplicate name attributes which will not bind to a collection and as a result the BillLists parameter will always be an empty collection (its also generating duplicate id attributes which is invalid html )

And in the controller I made a foreach to take each one of the list and update the required fields

Driver

[HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> LiquidaOpj(List<Opj> list, string FechaLiq)
    {
        var fecha = Convert.ToDateTime(FechaLiq);

        if(ModelState.IsValid)
        {
            foreach (var item in list)
            {
                var actualiza = await _context.Opj.Where(o => o.NroOrden.Equals(item.NroOrden)).FirstOrDefaultAsync();

                if (actualiza != null)
                {
                    actualiza.NroOrden = item.NroOrden;
                    actualiza.Liquidada = true;
                    actualiza.FechaLiq = fecha;
                }
            }
            await _context.SaveChangesAsync();
            return View("Success");
        }

        return View("AlgoNoEstaBien");

    }

In this case the field FechaLiq is the same value of another field that has the table so I put the same. And the field Liquidada I put true .

ALWAYS the Opjs that are within the filtering month will be liquidated.

I hope you could explain me and thanks for everything. Greetings

    
answered by 17.02.2018 / 20:41
source
0

ok the first thing we have is the view then we will send it through the checkboxes that are selected then it would be like this

 <form asp-action="LiquidaOpj">
        <table class="table">
            <thead>
                <tr>
                    <th>
                        @Html.DisplayNameFor(model => model.Presentacion)
                    </th>
                    <th>
                        @Html.DisplayNameFor(model => model.NroOrden)
                    </th>
                    <th>
                        @Html.DisplayNameFor(model => model.Caratula)
                    </th>
                    <th>
                        @Html.DisplayNameFor(model => model.DNI)
                    </th>
                    <th>
                        @Html.DisplayNameFor(model => model.Liquidada)
                    </th>
                    <th></th>
                </tr>
            </thead>
            <tbody>

                @foreach (var item in Model)
                {
                    <tr>
                        <td>
                            @Html.DisplayFor(modelItem => item.Presentacion)
                            <input name="FechaLiq" type="hidden" value="@item.Presentacion" />
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.NroOrden)
                            <input name="NroOrden" type="hidden" value="@item.NroOrden" />
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.Caratula)
                            <input name="Caratula" type="hidden" value="@item.Caratula" />
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.DNI)
                            <input name="Dni" type="hidden" value="@item.DNI" />
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.Liquidada)
                            <input name="Orden_Liquidar" type="hidden" value="@item.Orden_Id" >
                        </td>
                        <td>
                            <a asp-action="Details" asp-controller="Opjs" asp-route-id="@item.NroOrden">Detalle</a>
                        </td>
                    </tr>
                }
            </tbody>
        </table>
        <div class="form-group">
            <input type="submit" class="btn btn-success btn-sm" value="Generar" />
        </div>
    </form>

If you notice the only thing I did was to enable the checkbox and show it, so that when you send them, only the selected checkboxes will be sent in an array: remove these two properties style="display:none" checked="checked" and change the name of Liquidated to Order_Liquidar.

In the LiquidaOpj method:

[HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult>LiquidaOpj(int[] Orden_Liquidar)
    {
        if (Orden_Liquidar.Length == 0)
        {
            return NotFound();
        }
        foreach(var Item in Orden_Liquidar)
        {
        var opjToUpdate = await _context
        .Opj.SingleOrDefaultAsync(o => o.NroOrden == item);
        //aqui actualizas el elemento con tu codigo y lo almacenas
        }
        //guardamos cambios 
        try{
                await _context.SaveChangesAsync();
                return View("Success");
        }
        catch (DbUpdateException)
        {
        //Log the error (uncomment ex variable name and write a log.
        ModelState.AddModelError("", "Fallo al guardar los cambios. " +
                    "Intente nuevamente, si el error sigue " +
                    "comuníquese con el administrador.");
        }
        return View();
    }

The first thing we do is check if the arrangement does not come empty, that you will already validate it with JS in your view after this we go through each of the elements of it with a foreach, and inside the foreach we look for the element with the id that brings the arrangement and with that you can update the data.

    
answered by 16.02.2018 в 17:02