在 ASP.NET Core 中将数据保存到数据库时遇到问题

问题描述 投票:0回答:1

创建菜谱时,我的 ASP.NET Core MVC 应用程序遇到问题。该问题涉及无法将配方成分保存到数据库中。虽然主要配方详细信息已成功保存,但

RecipeIngredients
部分仍为空。

以下是我的代码相关部分的概述:

CreateModel
类中,我有一个方法
OnPostAsync
可以处理配方成分的保存。
Recipe.RecipeIngredient
属性应填充所选成分和数量。

在 HTML 表单中,我有一个部分,用户可以从下拉列表中选择成分,输入数量,然后根据所选成分自动选择单位。使用 JavaScript 动态添加成分。

我有一个

RecipeIngredient
类代表食谱和成分之间的关系。此类包括
IngredientID
Quantity
,以及对
Recipe
Ingredient
实体的引用。

我已验证

RecipeIngredientsInput
列表已在
OnGet
方法中正确初始化。

JavaScript 函数

addIngredientRow()
似乎可以正确地将成分添加到表单中。

问题似乎与数据未保存到数据库中的

RecipeIngredient
表有关。

调试:我尝试通过在

OnPostAsync
方法中放置断点来调试应用程序,并且
RecipeIngredientsInput
中的值似乎没有保存到数据库中。

如果有人遇到类似的问题或了解可能导致问题的原因,我将非常感谢您的帮助。此外,如果您需要更多详细信息或代码片段,请告诉我。

食谱

Create.cshtml.cs

using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc;
using proiect1.Models;
using System;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Authorization;

namespace proiect1.Pages.Recipes

{
    [Authorize(Roles = "Admin")]
    public class CreateModel : RecipeCategoriesPageModel
    {
        private readonly proiect1.Data.proiect1Context _context;
        private readonly IWebHostEnvironment _environment;
    
        public CreateModel(proiect1.Data.proiect1Context context, IWebHostEnvironment environment)
        {
            _context = context;
            _environment = environment;
        }
    
        [BindProperty]
        public Recipe Recipe { get; set; }
        public List<SelectListItem> AllIngredients { get; set; }
        public List<RecipeIngredientInputModel> RecipeIngredientsInput { get; set; }
    
        [BindProperty]
        public RecipePhoto RecipePhoto { get; set; }
        [BindProperty]
        public IFormFile Photo { get; set; }
    
        public IActionResult OnGet()
        {
            var recipe = new Recipe();
            recipe.RecipeCategories = new List<RecipeCategory>();
            recipe.RecipeIngredients = new List<RecipeIngredient>();

            PopulateAssignedCategoryData(_context, recipe);
            // Recipe.PublishingDate = DateTime.Now;
            PopulateIngredientsDropdown();

            RecipeIngredientsInput = new List<RecipeIngredientInputModel>();
    
            return Page();
        }
    
        private void PopulateIngredientsDropdown()
        {
            var ingredients = _context.Ingredient.Select(i => new SelectListItem
            {
                Value = i.Id.ToString(),
                Text = i.Name,
                Group = new SelectListGroup { Name = i.Unit } 
            })
            .ToList();
    
            AllIngredients = ingredients;
        }
    
        public async Task<IActionResult> OnPostAsync(string[] selectedCategories)
        {
            if (selectedCategories != null)
            {
                Recipe.RecipeCategories = selectedCategories
                    .Select(cat => new RecipeCategory { CategoryId = int.Parse(cat) })
                    .ToList();
            }
    
            if (RecipeIngredientsInput != null)
            {
                Recipe.RecipeIngredients = RecipeIngredientsInput
                    .Select(input => new RecipeIngredient
                    {
                        IngredientID = input.IngredientID,
                        Quantity = input.Quantity
                    })
                    .ToList();
            }
    
            if (Photo != null && Photo.Length > 0)
            {
                var directoryPath = Path.Combine(_environment.WebRootPath, "Recipe Photos");
    
                // Verifică dacă directorul există, altfel creează-l
                if (!Directory.Exists(directoryPath))
                {
                    Directory.CreateDirectory(directoryPath);
                }
    
                var photoPath = Path.Combine(directoryPath, Photo.FileName);

                using (var stream = new FileStream(photoPath, FileMode.Create))
                {
                    await Photo.CopyToAsync(stream);
                }
    
                RecipePhoto recipePhoto = new RecipePhoto
                {
                    Image = Photo,
                    ImagePath = Photo.FileName
                };
    
                _context.RecipePhotos.Add(recipePhoto);
                Recipe.Photo = Photo.FileName;
            }
    
            Recipe.PublishingDate = DateTime.Now;
           
            _context.Recipe.Add(Recipe);
            await _context.SaveChangesAsync();

            Recipe.Photo = Photo.FileName;

            return RedirectToPage("./Index");
        }
    }
    
    public class RecipeIngredientInputModel
    {
        public int IngredientID { get; set; }
        public decimal Quantity { get; set; }
    }
}

Recipe.cshtml

@page
@model proiect1.Pages.Recipes.CreateModel

@{
    ViewData["Title"] = "Create";
}

<script>
    function addIngredientRow() {
        var table = document.getElementById('ingredientTable');
        var row = table.insertRow(-1);

        // C1
        var select = document.createElement('select');
        select.name = 'RecipeIngredientsInput[' + table.rows.length + '].IngredientID';
        select.className = 'form-control';

        //data-unit
   @foreach (var ingredient in Model.AllIngredients)
{
    <text>
        var option = document.createElement('option');
        option.value = "@ingredient.Value";
        option.text = "@ingredient.Text";
        option.setAttribute('data-unit', "@ingredient.Group.Name");
        select.add(option);
    </text>
}

        row.insertCell(0).appendChild(select);

        // C2
        var quantityInput = document.createElement('input');
        quantityInput.type = 'text';
        quantityInput.name = 'RecipeIngredientsInput[' + table.rows.length + '].Quantity';
        quantityInput.className = 'form-control';
        row.insertCell(1).appendChild(quantityInput);

        // C3
        var unitText = document.createElement('span');
        unitText.className = 'form-control';
        unitText.innerHTML = '';
        row.insertCell(2).appendChild(unitText);

        select.addEventListener('change', function () {
            unitText.innerHTML = this.options[this.selectedIndex].getAttribute('data-unit');
        });
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', function () {
            addIngredientRow();
        });
    } else {
        addIngredientRow();
    }
</script>

<form method="post" enctype="multipart/form-data">
<h1>Create</h1>

<h4>Recipe</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <div class="form-group">
            <label asp-for="Recipe.Title" class="control-label"></label>
            <input asp-for="Recipe.Title" class="form-control" />
            <span asp-validation-for="Recipe.Title" class="text-danger"></span>
        </div>
        <div class="form-group">
            <label asp-for="Recipe.Description" class="control-label"></label>
            <input asp-for="Recipe.Description" class="form-control" />
            <span asp-validation-for="Recipe.Description" class="text-danger"></span>
        </div>

        <div class="form-group">
            <label asp-for="Recipe.Instructions" class="control-label"></label>
            <input asp-for="Recipe.Instructions" class="form-control" />
            <span asp-validation-for="Recipe.Instructions" class="text-danger"></span>
        </div>
         <div class="form-group">
                    <label asp-for="Recipe.RecipeIngredients" class="control-label">Ingredients</label>
                    <table id="ingredientTable">
                        <tr>
                            <th>Select Ingredient</th>
                            <th>Enter Quantity</th>
                            <th>Unit</th>
                        </tr>
                    </table>
                    <button type="button" onclick="addIngredientRow()">Add Ingredient</button>
                    <span asp-validation-for="Recipe.RecipeIngredients" class="text-danger"></span>
                </div>
        <div class="form-group">
            <label asp-for="Recipe.Photo" class="control-label"></label>
            <div class="custom-file">
                <input type="file" asp-for="Photo" class="custom-file-input" accept="image/*" />
 
            </div>
            <span asp-validation-for="Photo" class="text-danger"></span>
        </div>

        <div class="form-group">
            <label asp-for="Recipe.PublishingDate" class="control-label"></label>
           <input asp-for="Recipe.PublishingDate" type="hidden" />

            <span asp-validation-for="Recipe.PublishingDate" class="text-danger"></span>
        </div>
         <div class="form-group">
                             <div class="table">
                               <table>
                                 <tr>
                                    @{
                                         int cnt = 0;
                                         foreach (var cat in Model.AssignedCategoryDataList)
                                     {
                                             if (cnt++ % 3 == 0)
                                              {
                                                 @:</tr><tr>
                                                 }
                                                @:<td>
                                               <input type="checkbox"
                                                     name="selectedCategories"
                                                    value="@cat.CategoryID"
                                                     @(Html.Raw(cat.Assigned ?"checked=\"checked\"" : "")) />
                                             @cat.CategoryID @: @cat.Name
                                          @:</td>
                                        }
                                     @:</tr>
                                     }
                              </table>
                         </div>
                     </div>
        <div class="form-group">
            <input type="submit" value="Create" class="btn btn-primary" />
        </div>
    </div>
</div>

<div>
    <a asp-page="Index">Back to List</a>
</div>
</form>

Recipe.cs

using System.ComponentModel.DataAnnotations;

namespace proiect1.Models
{
    public class Recipe
    {
        public int Id { get; set; }

        [Display(Name = "Recipe Title")]
        public string? Title { get; set; }

        [Display(Name = "Recipe Description")]
        public string? Description { get; set; }

        [Display(Name = "Recipe Instructions")]
        public string? Instructions { get; set; }

        // [Display(Name = "Recipe Photo")]
        public string? Photo { get; set; }

        [DataType(DataType.Date)]
        public DateTime PublishingDate { get; set; }

        public ICollection<RecipeIngredient>? RecipeIngredients { get; set; }

        public int? SavedRecipeId { get; set; }
        public SavedRecipe? SavedRecipe { get; set; }

        public ICollection<RecipeCategory>? RecipeCategories { get; set; }

        public int? UserId { get; set; }
    }
}

Ingredient.cs

namespace proiect1.Models
{
    public class Ingredient
    {
        public int Id { get; set; }

        public string? Name { get; set; }
        public string? Unit { get; set; } //grame, lingurita, ml,...

        public ICollection<RecipeIngredient>? RecipeIngredients { get; set; }
    }
}

RecipeIngredient.cs

using proiect1.Models;
using System.ComponentModel.DataAnnotations.Schema;

namespace proiect1.Models
{
    public class RecipeIngredient
    {
        public int Id { get; set; }

        [ForeignKey("Recipe")]
        public int RecipeID { get; set; }
        public Recipe? Recipe { get; set; }

        public int IngredientID { get; set; }
        public Ingredient? Ingredient { get; set; }
        [Column(TypeName = "decimal(6, 0)")]
        public decimal Quantity { get; set; }
    }
}
c# database asp.net-core-mvc
1个回答
0
投票

并不是数据库没有存储成分,而是数据没有正确绑定。有两个地方需要修改。

  1. Create.cshtml.cs需要[bindproperty]属性
[BindProperty]    //1.the attribute needs to be added on RecipeIngredientsInput
public List<RecipeIngredientInputModel> RecipeIngredientsInput { get; set; }
  1. cshtml中基于行的数字可能会导致计数错误,请将其替换为Create.cshtml中的索引。
<script>
    var index = 0;
    function addIngredientRow() {
        var table = document.getElementById('ingredientTable');
        var row = table.insertRow(-1);

        // C1
        var select = document.createElement('select');
        select.name = 'RecipeIngredientsInput[' + index + '].IngredientID';
        select.className = 'form-control';

        //data-unit
       @foreach (var ingredient in Model.AllIngredients)
        {
            <text>
                var option = document.createElement('option');
                option.value = "@ingredient.Value";
                option.text = "@ingredient.Text";
                option.setAttribute('data-unit', "@ingredient.Group.Name");
                select.add(option);
            </text>
        }

        row.insertCell(0).appendChild(select);

        // C2
        var quantityInput = document.createElement('input');
        quantityInput.type = 'text';
        quantityInput.name = 'RecipeIngredientsInput[' + index + '].Quantity';
        quantityInput.className = 'form-control';
        row.insertCell(1).appendChild(quantityInput);

        // C3
        var unitText = document.createElement('span');
        unitText.className = 'form-control';
        unitText.innerHTML = '';
        row.insertCell(2).appendChild(unitText);

        select.addEventListener('change', function () {
            unitText.innerHTML = this.options[this.selectedIndex].getAttribute('data-unit');
        });
        index++;
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', function () {
            addIngredientRow();
        });
    } else {
        addIngredientRow();
    }
</script>

© www.soinside.com 2019 - 2024. All rights reserved.