You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MVC新手求助:食谱与食材多对多数据库模型构建及联表查询问题

食谱与食材数据库设计及MVC实现方案

一、数据库表设计(4张核心表)

针对食谱与食材的多对多关系,搭配分类管理,设计以下4张表:

1. 食材分类表 (categories)

  • category_id (INT, 主键, 自增): 分类唯一标识
  • category_name (VARCHAR(50), 非空): 分类名称(如蔬菜、肉类、调料)

2. 食材表 (ingredients)

  • ingredient_id (INT, 主键, 自增): 食材唯一标识
  • ingredient_name (VARCHAR(100), 非空): 食材名称(如西红柿、牛腩)
  • category_id (INT, 外键关联 categories.category_id): 所属分类ID
  • unit (VARCHAR(20)): 计量单位(如克、个、勺)

3. 食谱表 (recipes)

  • recipe_id (INT, 主键, 自增): 食谱唯一标识
  • recipe_name (VARCHAR(100), 非空): 食谱名称(如西红柿炖牛腩)
  • description (TEXT): 食谱简介
  • cooking_steps (TEXT): 烹饪步骤

4. 食谱-食材关联表 (recipe_ingredients)

这张表用来解决食谱和食材的多对多关系:

  • recipe_id (INT, 外键关联 recipes.recipe_id): 关联的食谱ID
  • ingredient_id (INT, 外键关联 ingredients.ingredient_id): 关联的食材ID
  • quantity (DECIMAL(10,2)): 食材用量
  • 联合主键:(recipe_id, ingredient_id),避免同一个食谱重复关联同一个食材

二、MVC各层实现步骤

1. 模型层(Model)

先定义对应表的实体类(以C#为例,其他语言逻辑一致):

// 分类实体
public class Category
{
    public int CategoryId { get; set; }
    public string CategoryName { get; set; }
    public List<Ingredient> Ingredients { get; set; }
}

// 食材实体
public class Ingredient
{
    public int IngredientId { get; set; }
    public string IngredientName { get; set; }
    public int CategoryId { get; set; }
    public string Unit { get; set; }
    public Category Category { get; set; }
    public List<RecipeIngredient> RecipeIngredients { get; set; }
}

// 食谱实体
public class Recipe
{
    public int RecipeId { get; set; }
    public string RecipeName { get; set; }
    public string Description { get; set; }
    public string CookingSteps { get; set; }
    public List<RecipeIngredient> RecipeIngredients { get; set; }
}

// 食谱-食材关联实体
public class RecipeIngredient
{
    public int RecipeId { get; set; }
    public int IngredientId { get; set; }
    public decimal Quantity { get; set; }
    public Recipe Recipe { get; set; }
    public Ingredient Ingredient { get; set; }
}

数据访问核心操作:

  • 查询所有分类及下属食材,用于创建食谱时展示选项
  • 保存流程:先存食谱得到recipe_id,再批量保存关联表的食材记录

2. 视图层(View)

创建食谱的页面需要包含两部分:食谱基本信息、食材选择区。示例简化结构:

<form method="post" action="/Recipe/Create">
    <!-- 食谱基本信息 -->
    <input type="text" name="RecipeName" placeholder="食谱名称" required>
    <textarea name="Description" placeholder="食谱简介"></textarea>
    <textarea name="CookingSteps" placeholder="烹饪步骤" required></textarea>

    <!-- 食材选择区 -->
    <h3>选择食材</h3>
    @foreach (var category in Model.Categories)
    {
        <h4>@category.CategoryName</h4>
        @foreach (var ingredient in category.Ingredients)
        {
            <div>
                <input type="checkbox" name="SelectedIngredients" value="@ingredient.IngredientId">
                <label>@ingredient.IngredientName</label>
                <input type="number" name="Quantity_@ingredient.IngredientId" step="0.1" placeholder="用量(@ingredient.Unit)">
            </div>
        }
    }

    <button type="submit">保存食谱</button>
</form>

3. 控制器层(Controller)

处理创建请求的核心逻辑:

public class RecipeController : Controller
{
    private readonly YourDbContext _dbContext;

    public RecipeController(YourDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    // 展示创建页面
    public IActionResult Create()
    {
        var viewModel = new CreateRecipeViewModel
        {
            // 加载所有分类及下属食材
            Categories = _dbContext.Categories.Include(c => c.Ingredients).ToList()
        };
        return View(viewModel);
    }

    // 处理提交请求
    [HttpPost]
    public IActionResult Create(Recipe recipe, int[] SelectedIngredients, Dictionary<string, decimal> Quantity)
    {
        if (ModelState.IsValid)
        {
            // 1. 先保存食谱到数据库,生成recipe_id
            _dbContext.Recipes.Add(recipe);
            _dbContext.SaveChanges();

            // 2. 批量处理选中的食材
            foreach (var ingredientId in SelectedIngredients)
            {
                // 获取对应食材的用量
                if (Quantity.TryGetValue($"Quantity_{ingredientId}", out var quantity))
                {
                    var recipeIngredient = new RecipeIngredient
                    {
                        RecipeId = recipe.RecipeId,
                        IngredientId = ingredientId,
                        Quantity = quantity
                    };
                    _dbContext.RecipeIngredients.Add(recipeIngredient);
                }
            }
            _dbContext.SaveChanges();
            return RedirectToAction("Index");
        }

        // 验证失败,返回页面并保留输入内容
        var viewModel = new CreateRecipeViewModel
        {
            Categories = _dbContext.Categories.Include(c => c.Ingredients).ToList(),
            Recipe = recipe
        };
        return View(viewModel);
    }
}

三、核心问题解决:创建食谱时如何选取全部食材

  1. 展示食材选项:视图层通过数据库关联查询,把所有食材按分类展示给用户,用户可勾选需要的食材并填写用量
  2. 保存关联关系:控制器接收选中的食材ID数组和对应用量,在食谱保存成功后,将食谱ID、食材ID、用量批量存入关联表
  3. 查询食谱食材:后续要查看某食谱的全部食材,只需通过recipe_id关联查询recipe_ingredients和ingredients表即可

内容的提问来源于stack exchange,提问作者baba

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 07:35:18