簡體   English   中英

FK連接的object及其相關的object如何更新。 ASP.NET 核心 MVC

[英]How to update object and its related object which are connected with FK. ASP.NET Core MVC

我想更新 object 及其與 FK 連接的相關對象。 例如,

我有 class 稱為“項目”

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace RandApp.Models
{
    public class Item : BaseEntity
    {
        [Required]
        [Display(Name = "Item Photo")]
        public string ItemPhoto { get; set; }
        [Required]
        [Display(Name = "Item Type")]
        public string ItemType { get; set; }
        [Required]
        [Display(Name = "Item Category")]
        public string ItemCategory { get; set; }
        [Required]
        [Display(Name = "Item Name")]
        public string Name { get; set; }
        [Required]
        [Display(Name = "Item Colors")]
        public List<ItemColors> Color { get; set; } = new List<ItemColors>();
        [Required]
        [Display(Name = "Item Size")]
        public List<ItemSizes> Size { get; set; } = new List<ItemSizes>();
        [Required]
        [Display(Name = "Item Material Type")]
        public string MaterialType { get; set; }
        [Required]
        [Display(Name = "Designed For")]
        public string DesignedFor { get; set; }
        [Required]
        [Display(Name = "Item Price")]
        public double Price { get; set; }
        [Required]
        [Display(Name = "Item Description")]
        public string Description { get; set; }
    }
}

如您所見,我列出了“ItemColors”和“ItemSizes”類型,這些是它們的類ItemColors

using System.ComponentModel.DataAnnotations.Schema;

namespace RandApp.Models
{
    public class ItemColors : BaseEntity
    {
        public string ItemColor { get; set; }
        public int? ItemId { get; set; }
        [ForeignKey("ItemId")]
        public Item Item { get; set; }
    }
}

物品尺寸

using System.ComponentModel.DataAnnotations.Schema;

namespace RandApp.Models
{
    public class ItemSizes : BaseEntity
    {
        public string ItemSize { get; set; }
        public int? ItemId { get; set; }
        [ForeignKey("ItemId")]
        public Item Item { get; set; }
    }
}

所以我的下一個問題是:假設我已經創建了一些項目(例如運動衫)並且它有 colors:黑色,灰色,棕色並且它有尺寸:S,M。 因此,當我想更新此項目並添加一種顏色(如紅色或藍色)時,它不會更新,它只會在已存在的列表中添加此 colors 並重新上傳數據。 (如果我有黑色、灰色、棕色,然后添加紅色,現在我將有:“黑色、灰色、棕色、黑色、灰色、棕色、紅色”)。

有“項目”更新視圖:

@model RandApp.DTOs.ItemDto

<h4>Update Item</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="UpdateItem">
            <input asp-for="Id" hidden />
            <div class="form-group">
                <label asp-for="@Model.ItemPhoto" class="control-label"></label>
                <img src="~/assets/@Model.ItemPhoto" style="width:230px; height:300px; object-fit:cover" class="form-control" />
                <input asp-for="@Model.ItemPhoto" hidden />
                <span asp-validation-for="@Model.ItemPhoto" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="@Model.Name" class="control-label"></label>
                <input asp-for="@Model.Name" class="form-control" />
                <span asp-validation-for="@Model.Name" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="@Model.DesignedFor" class="control-label"></label>
                <select asp-for="@Model.DesignedFor" class="form-control">
                    @foreach (var desigendFor in Enum.GetValues(typeof(RandApp.Enums.DesignedFor)))
                    {
                        <option val="@desigendFor" value="@desigendFor.ToString()">@desigendFor</option>
                    }
                </select>
                <span asp-validation-for="@Model.DesignedFor" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="@Model.ItemCategory" class="control-label"></label>
                <select asp-for="@Model.ItemCategory" class="form-control">
                    <option>@Model.ItemCategory</option>
                </select>
                <span asp-validation-for="@Model.ItemCategory" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="@Model.ItemType" class="control-label"></label>
                <select asp-for="@Model.ItemType" class="form-control">
                    <option>@Model.ItemType</option>
                </select>
                <span asp-validation-for="@Model.ItemType" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="@Model.MaterialType" class="control-label"></label>
                <select asp-for="@Model.MaterialType" class="form-control">
                    <option value="" selected>Select Material Type</option>
                    @foreach (var materialType in Enum.GetValues(typeof(RandApp.Enums.MaterialType)))
                    {
                        <option value="@materialType.ToString()">@materialType</option>
                    }
                    <option value="Other">Other</option>
                </select>
                <input id="otherMaterialInp" asp-for="@Model.MaterialType" class="form-control" style="display:none; margin-top:8px" placeholder="Enter Material Type" />
                <span asp-validation-for="@Model.MaterialType" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="@Model.Color" class="control-label"></label>
                <select asp-for="@Model.Color" class="form-control">
                    @foreach (var color in Enum.GetValues(typeof(RandApp.Enums.ItemColor)))
                    {
                        <option value="@color">@color</option>
                    }
                    <option value="Other">Other</option>
                </select>
                <!-- This hidden select is used to get only selected colors of current item -->
                <select hidden multiple class="form-control" id="SelectedColors">
                    @foreach (var color in Model.Color)
                    {
                        <option value="@color.ItemColor">@color.ItemColor</option>
                    }
                </select>
                <span asp-validation-for="@Model.Color" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="@Model.Size" class="control-label"></label>
                <select asp-for="@Model.Size" class="form-control">
                </select>
                <!-- This hidden select is used to get only selected sizes of current item -->
                <select hidden multiple class="form-control" id="SelectedSizes">
                    @foreach (var size in Model.Size)
                    {
                        <option value="@size.ItemSize">@size.ItemSize</option>
                    }
                </select>
                <span asp-validation-for="@Model.Size" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="@Model.Price" class="control-label"></label>
                <input asp-for="@Model.Price" class="form-control" />
                <span asp-validation-for="@Model.Price" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="@Model.Description" class="control-label"></label>
                <textarea asp-for="@Model.Description" class="form-control"></textarea>
                <span asp-validation-for="@Model.Description" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Update" class="btn btn-primary" />
                <a asp-controller="Admin" asp-action="Index" class="btn btn-primary">Go Back</a>
            </div>
        </form>
    </div>
</div>
@section Scripts
{
    <script>
        var selectedItemTypeVal = $("#ItemType").val();
        var selectedDesignedVal = $("#DesignedFor").val();
        var selectedCategoryVal = $("#ItemCategory").val();
        var itemColors = new Array();
        var itemSizes = new Array();
        $(document).ready(function () {
            if ($("#DesignedFor").val() != "") {
                $.ajax({
                    url: '@Url.Action("LoadItemCategories","Admin")',
                    type: 'GET',
                    dataType: 'json',
                    data: { designedFor: selectedDesignedVal },
                    success: function (res) {
                        $('#ItemCategory').html('');
                        $.each(res, function (val, text) {
                            $('#ItemCategory').append(
                                $('<option></option>').val(text).html(text)
                            );
                        });
                    },
                    error: function (err) {
                        console.log(err.responseText);
                    }
                });
            }

            if ($("#ItemCategory").val() != "") {
                $.ajax({
                    url: '@Url.Action("LoadItemTypes", "Admin")',
                    type: 'GET',
                    dataType: 'json',
                    data: { designedFor: selectedDesignedVal, category: selectedCategoryVal },
                    success: function (res) {
                        $('#ItemType').html('');
                        $.each(res, function (val, text) {
                            $('#ItemType').append(
                                $('<option></option>').val(text).html(text)
                            );
                        });
                    },
                    error: function (err) {
                        console.log(err.responseText);
                    }
                });
            }

            if ($("#ItemType").val() != "") {
                if (selectedCategoryVal.toLowerCase() == "clothing" || selectedCategoryVal.toLowerCase() == "shoes") {
                    $.ajax({
                        url: '@Url.Action("LoadItemSize", "Admin")',
                        type: 'GET',
                        dataType: 'json',
                        data: { designedFor: selectedDesignedVal, category: selectedCategoryVal },
                        success: function (res) {
                            $.each(res, function (val, text) {
                                $('#Size').append(
                                    $('<option></option>').val(text).html(text)
                                );
                                itemSizes.push(text);
                            });
                            $("#SelectedSizes option").each(function () {
                                for (var i = 0; i < itemSizes.length; i++) {
                                    if ($(this).val() == itemSizes[i]) {
                                        $("[value=" + itemSizes[i] + "]").attr("selected", "selected");
                                    }
                                }
                            });
                        },
                        error: function (err) {
                            console.log(err.responseText);
                        }
                    });
                } else {
                    $.ajax({
                        url: '@Url.Action("LoadItemSizes", "Admin")',
                        type: 'GET',
                        dataType: 'json',
                        data: { designedFor: selectedDesignedVal, category: selectedCategoryVal, itemType: selectedItemTypeVal },
                        success: function (res) {
                            $.each(res, function (val, text) {
                                // This "1" means "SingleSize" enum value
                                if (text == 1) {
                                    $('#Size').append(
                                        $('<option></option>').val(text).html("Single Size")
                                    );
                                } else {
                                    $('#Size').append(
                                        $('<option></option>').val(text).html(text + " CM")
                                    );
                                }
                            });
                        },
                        error: function (err) {
                            console.log(err.responseText);
                        }
                    });
                }
            }

            if ($("#Color option").val() != "") {
                $("#Color option").each(function () {
                    itemColors.push($(this).val());
                })
                $("#SelectedColors option").each(function () {
                    for (var i = 0; i < itemColors.length; i++) {
                        if ($(this).val() == itemColors[i]) {
                            $("[value=" + itemColors[i] + "]").attr("selected", "selected");
                        }
                    }
                });
            }
        });

        function SetValue(input) {
            var fileName = input.files[0].name;
            //asp-for will generate the id and name
            //so you can get the selector by using $("#ItemPhoto")
            $("#ItemPhoto").val(fileName);
        };

        // displays "other option" input in order to enter custom material type
        // if desired is not given in the list
        $('#MaterialType').on('change', function () {
            var selectedMaterialTypeVal = $(this).val();
            if (selectedMaterialTypeVal.toLowerCase() == "other") {
                $('#MaterialType').attr('disabled', 'disabled');
                $('#otherMaterialInp').show();
            } else {
                $('#MaterialType').removeAttr('disabled');
                $('#otherMaterialInp').hide();
            }
        });
    </script>
}

並且有“項目” Controller

// GET Update
        public async Task<IActionResult> UpdateItem(int id)
        {
            if (id == 0)
            {
                return NotFound();
            }
            var item = await _itemRepo.Get().Include(o => o.Color).Include(o => o.Size).FirstOrDefaultAsync(o => o.Id == id);
            if (item == null)
            {
                return NotFound();
            }

            var result = _mapper.Map<ItemDto>(item);
            return View(result);
        }

        // POST Update
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> UpdateItem(Item item, List<string> Color, List<string> Size)
        {
            if (!ModelState.IsValid)
            {
                return View();
            }

            foreach (var color in Color)
            {
                item.Color.Add(new ItemColors() { ItemId = item.Id, ItemColor = color });
            }
            foreach (var size in Size)
            {
                item.Size.Add(new ItemSizes() { ItemId = item.Id, ItemSize = size });
            }

            await _itemRepo.UpdateAsync(item);
            return RedirectToAction("Index");
        }

會不會是FK的問題? 或者是否有類似 Cascade Delete 的解決方案但用於更新或我能做什么?

您的代碼的行為是正確的,正如您所描述的那樣。
問題在於您的更新邏輯的實現。

  1. 在您添加新的顏色或尺寸之前 - 您應該檢查它是否已經存在於項目中。 僅在不存在時添加。
  2. 您可以刪除顏色。 在這種情況下,您應該找到一種存在於您的項目中但不存在於您的參數列表 colors 中的顏色。

最簡單但不是最好的解決方案是從項目中刪除所有 colors,然后添加參數中的所有內容。

我的建議是找到應該刪除的內容和應該添加的內容。 然后更新。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM