【问题标题】:How to update multiple rows at once from a View (ASP.NET - Core)如何从视图一次更新多行(ASP.NET - 核心)
【发布时间】:2021-03-24 17:06:26
【问题描述】:

我正在尝试创建一个可以一次编辑多个值的视图。该视图由列表中的多行组成,我想在其中选中一个复选框以将布尔值 EnableAlertsUpload 更改为 TrueFalse,如下图所示:

当按下更新按钮时,应该调用IActionResult Edit,它会更新数据库中的所有EnableAlertsUpload 布尔值。该数据库是使用带有 Entity Framework Core 的 Code First 方法制作的。

当我现在按下更新按钮时,将创建一条新记录,并且所有值都设置为NULL。所以看来我在存储库中的SaveDevice 方法存在问题

警报控制器

    public ViewResult Devices()
        => View(new DevicesViewModel
        {
            Devices = repo.getDevices()
        });

    [HttpPost]
    public IActionResult Edit(Devices devices)
    {
        repo.SaveDevice(devices);

        return RedirectToAction();
    }

存储库

    public void SaveDevice(Devices devices)
    {
        if (devices.objid == 0)
        {
            db.Devices.Add(devices);
        }
        else
        {
            Devices dbEntry = db.Devices
                .FirstOrDefault(p => p.objid == devices.objid);
            if (dbEntry != null)
            {
                dbEntry.objid = devices.objid;
                dbEntry.device = devices.device;
                dbEntry.group = devices.group;
                dbEntry.host = devices.host;
                dbEntry.EnableAlertsUpload = devices.EnableAlertsUpload;
            }
        }
        db.SaveChanges();
    }

设备

public partial class Devices
{
    [Key()]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int objid { get; set; }
    public string group { get; set; }
    public string device { get; set; }
    public string host { get; set; }
    public bool EnableAlertsUpload { get; set; }
}

DevicesViewModel

public class DevicesViewModel : PageModel
{
    [BindProperty]
    public List<Devices> Devices { get; set; }
}

设备视图

@model Models.ViewModels.DevicesViewModel  
  
<form asp-action="Edit" method="post">
    <table class="table">
        <tr>
            <th>Id</th>
            <th>Device</th>
            <th>Group</th>
            <th>Host</th>
            <th>Enabled Alerts Update</th>
        </tr>
        @for (var i = 0; i < Model.Devices.Count(); i++)
        {
            <tr>
                <td>
                    <input type="hidden" asp-for="Devices[i].objid" />
                    @Model.Devices[i].objid
                </td>
                <td>@Model.Devices[i].device</td>
                <td>@Model.Devices[i].group</td>
                <td>@Model.Devices[i].host</td>
                <td><input asp-for="Devices[i].EnableAlertsUpload"/></td>
            </tr>
        }
    </table>
    <button input type="submit" value="Edit">Update</button>
</form>

【问题讨论】:

  • 您的 POST 编辑方法只需要一个 Devices 对象,而不是它们的集合。试试public IActionResult Edit(Devices[] devices)。您的存储库方法也需要更改以期望设备列表。然后,您将需要对它们进行 foreach 循环。

标签: asp.net-mvc asp.net-core entity-framework-core blazor


【解决方案1】:

首先,根据代码sn-ps(在控制器方法中)看来,您的应用程序是Asp.Net Core MVC 应用程序,对吧?如果是这样的话,我认为DeviceViewModel模型是不需要继承PageModel的(一般RazorPage中使用PageModel)。因为看起来如果我们在 Asp.net Core MVC 应用程序中使用它,它会show An unhandled exception occurred while processing the request exception

因此,对于 Asp.net Core MVC 应用程序,我建议您可以如下修改您的代码(删除 PageModel):

public class DevicesViewModel 
{       
    public List<Devices> Devices { get; set; }
}

当我现在按下更新按钮时,将创建一条新记录 并且所有值都设置为 NULL。所以看来我的有问题 存储库中的 SaveDevice 方法

那么,对于上面的问题,我们可以在Devices View中看到,view model是DevicesViewModel ,所以,点击Update按钮后会提交这个model,而不是Devices model。而且,在Devices视图中,由于直接将数据显示到&lt;td&gt;标签中,提交表单后,这些属性值将是null,你可以在Edit方法中设置断点进行验证。

要解决上述问题,在设备视图中,您可以使用隐藏字段控件来显示属性值,在编辑操作方法中您可以使用DevicesViewModel

您可以参考以下代码:

型号代码:

public class Devices
{
    [Key()]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int objid { get; set; }
    public string group { get; set; }
    public string device { get; set; }
    public string host { get; set; }
    public bool EnableAlertsUpload { get; set; }
}
public class DevicesViewModel 
{       
    public List<Devices> Devices { get; set; }
}

设备视图中的代码:

    @model MVCDemo.Models.DevicesViewModel 
    <form asp-action="Edit" method="post">
        <table class="table">
            <tr>
                <th>Id</th>
                <th>Device</th>
                <th>Group</th>
                <th>Host</th>
                <th>Enabled Alerts Update</th>
            </tr>
            @for (var i = 0; i < Model.Devices.Count(); i++)
            {
                <tr>
                    <td>
                        <input type="hidden" asp-for="Devices[i].objid" />
                        @Model.Devices[i].objid
                    </td>
                    <td>
                        <input type="hidden" asp-for="Devices[i].device" />
                        @Model.Devices[i].device
                    </td>
                    <td>
                        <input type="hidden" asp-for="Devices[i].group" />
                        @Model.Devices[i].group
                    </td>
                    <td>
                        <input type="hidden" asp-for="Devices[i].host" />
                        @Model.Devices[i].host
                    </td>
                    <td><input asp-for="Devices[i].EnableAlertsUpload" /></td>
                </tr>
            }
        </table>
        <button input type="submit" value="Edit">Update</button>
    </form>

编辑操作中的代码:

    [HttpPost]
    public IActionResult Edit(DevicesViewModel device)
    {
        if(device != null && device.Devices.Count>0)
        {
            //Since there might have multiple devices, use a foreach statement to loop though the devices and call the SaveDevice method to update data.
            foreach (var item in device.Devices)
            {
                repo.SaveDevice(item);
            }
        }
        return RedirectToAction(nameof(Index));
    }

截图如下:

最后,如果要编辑字符串类型属性值,在设备视图中,可以使用以下代码显示该值。

    <input asp-for="@Model.Devices[i].device" class="form-control" />

【讨论】:

  • 哇,感谢您提供的惊人答案和清晰的解释,这正是我想要的,一切都按预期工作:)。我对 ViewModel 的使用感到有些困惑,似乎我把 Devices Object 和 ViewModel 搞混了。我将花一些时间来研究这个主题以完全理解这个过程。再次感谢您花时间以如此清晰的方式回答我的问题!
  • 我想知道您是如何如此快速地重新创建项目的。是否有任何具有基本 CRUD 功能和身份框架的模板(因为我还看到了注册按钮)。如果是这样,请告诉我在哪里可以找到它?
  • 嗨@Bram,对于基本的CRUD功能,我也是使用EF核心,生成数据库并配置dbcontext(Repository)后,我们可以直接通过dbcontext实现CRUD功能,你可以参考following tutorial。对于身份,您可以在应用程序中使用脚手架身份,检查this link
【解决方案2】:

输入不是直接更新绑定您的列表,但checkboxfor 可以。因为checkboxfor会自动添加一个checkbox类型的隐藏字段。

<td>@Html.CheckBoxFor(m => m.Devices[i].EnableAlertsUpload)</td>

否则你可以更新你的剃刀视图

<td><input asp-for="Devices[i].EnableAlertsUpload"/>
 <input type="hidden" asp-for="Devices[i].EnableAlertsUpload" />
</td>

【讨论】:

    猜你喜欢
    • 2020-01-07
    • 1970-01-01
    • 2020-12-06
    • 1970-01-01
    • 2020-12-26
    • 2021-08-08
    • 1970-01-01
    • 2019-10-24
    相关资源
    最近更新 更多