ASP.NET Core结合PostgreSQL实现文件上传表单级联下拉的问题咨询
插入Genre数据报错基本都是外键约束冲突导致:PostgreSQL要求你插入的Genre表
FileTypeID字段的值,必须已经在FileType表的主键字段中存在。操作顺序应该是先向FileType表插入所有需要的类型数据,再向Genre表插入对应FileTypeID的分类数据即可解决报错。
级联下拉功能实现步骤
步骤1:调整FileUploadViewModel
public class FileUploadViewModel { // 原有属性保持不变 public int FileTypeId { get; set; } // 新增:选中的文件类型ID public int Genre { get; set; } // 原有枚举类型改为int,对应数据库Genre表主键 // 其他属性:Name、Author、Description、PublishedOn、Files 保持不变 }
步骤2:调整Controller逻辑
首先修改首页加载动作,预加载FileType下拉选项:
public IActionResult Index() { // 从PostgreSQL查询所有文件类型,转为下拉选项 ViewBag.FileTypeList = new SelectList(_dbContext.FileTypes.ToList(), "Id", "Name"); return View(); }
新增获取分类列表的接口,用于前端动态加载:
[HttpGet] public IActionResult GetGenresByFileTypeId(int fileTypeId) { var genres = _dbContext.Genres .Where(g => g.FileTypeId == fileTypeId) .Select(g => new { id = g.Id, name = g.Name }) .ToList(); return Json(genres); }
步骤3:修改Razor视图表单
在原有Genre下拉框前面新增FileType下拉框,替换原有Genre下拉的枚举绑定:
@model FileUploadViewModel @{ ViewData["Title"] = "Index";} <h4>Start Uploading Files Here</h4> <hr /> @if (ViewBag.Message != null) { <div class="alert alert-success alert-dismissible" style="margin-top:20px"> @ViewBag.Message </div> } <form enctype="multipart/form-data" asp-controller="files" asp-action="UploadToFileSystem" method="post"> <div class="form-group row"> <label asp-for="Name" class="col-sm-2 col-form-label"></label> <div class="col-sm-10"> <input asp-for="Name" class="form-control" placeholder="name" /> <span asp-validation-for="Name" class="text-danger"></span> </div> </div> <div class="form-group row"> <label asp-for="Author" class="col-sm-2 col-form-label"></label> <div class="col-sm-10"> <input asp-for="Author" class="form-control" placeholder="Author" /> <span asp-validation-for="Author" class="text-danger"></span> </div> </div> <!-- 新增FileType下拉框 --> <div class="form-group row"> <label asp-for="FileTypeId" class="col-sm-2 col-form-label"> 文件类型 </label> <div class="col-sm-10"> <select asp-for="FileTypeId" class="custom-select mr-sm-2" asp-items="ViewBag.FileTypeList" id="fileTypeSelect"> <option value="">请选择文件类型</option> </select> </div> </div> <!-- 修改原有Genre下拉框,移除枚举绑定 --> <div class="form-group row"> <label asp-for="Genre" class="col-sm-2 col-form-label"> 分类 </label> <div class="col-sm-10"> <select asp-for="Genre" class="custom-select mr-sm-2" id="genreSelect"> <option value="">请先选择文件类型</option> </select> <span asp-validation-for="Genre" class="text-danger"></span> </div> </div> <div class="form-group row"> <label asp-for="Description" class="col-sm-2 col-form-label"></label> <div class="col-sm-10"> <input asp-for="Description" class="form-control" placeholder="Description" /> <span asp-validation-for="Description" class="text-danger"></span> </div> </div> <div class="form-group row " > <label asp-for="PublishedOn" class="col-sm-2 col-form-label"></label> <div class="col-sm-10"> <input type="date" asp-for="PublishedOn" class="form-control" placeholder="Publishing Date" /> <span asp-validation-for="PublishedOn" class="text-danger"></span> </div> </div> <div class="form-group row"> <label asp-for="Files" class="col-sm-2 col-form-label"></label> <div class="col-sm-10"> <div class="custom-file"> <input asp-for="Files" multiple type="file" class="form-control custom-file-input" placeholder="file" /> <label class="custom-file-label">Chose File...</label> <span asp-validation-for="Files" class="text-danger"></span> </div> </div> </div> <button class="btn btn-success" type="submit" asp-action="UploadToFileSystem" asp-controller="Files">Upload</button> </form>
步骤4:新增级联交互脚本
在原有Scripts块中添加FileType下拉的监听逻辑:
@section Scripts{ <script> $(document).ready(function () { // 原有文件选择展示逻辑保持不变 $('.custom-file-input').on("change", function () { var fileLabel = $(this).next('.custom-file-label'); var files = $(this)[0].files; if (files.length > 1) { fileLabel.html(files.length + 'files selected'); } else if (files.length == 1) { fileLabel.html(files[0].name); } }); // 新增级联下拉逻辑 $('#fileTypeSelect').on('change', function () { const fileTypeId = $(this).val(); const genreSelect = $('#genreSelect'); // 清空原有选项 genreSelect.empty(); if (!fileTypeId) { genreSelect.append('<option value="">请先选择文件类型</option>'); return; } // 请求后端获取对应分类 $.get('/Files/GetGenresByFileTypeId?fileTypeId=' + fileTypeId, function (data) { genreSelect.append('<option value="">请选择分类</option>'); // 渲染返回的分类选项 data.forEach(genre => { genreSelect.append(`<option value="${genre.id}">${genre.name}</option>`); }); }); }); }); </script> }
备选方案(适合数据量小的场景)
如果FileType和Genre总数据量很小,可以直接在页面渲染时把所有Genre数据按FileTypeID分组序列化到前端,选择时直接本地过滤,无需发AJAX请求,性能更好:
- 在Controller的Index动作中添加:
ViewBag.AllGenres = System.Text.Json.JsonSerializer.Serialize(_dbContext.Genres.ToList());
- 前端直接读取
ViewBag.AllGenres做本地过滤即可,无需调用后端接口。
内容的提问来源于stack exchange,提问作者DevGary
相关产品推荐
相关产品推荐

