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

ASP.NET Core MVC:数据库优先模式下从SQL Server函数填充模型

ASP.NET Core MVC 数据库优先 CRUD 实战方案

1. 让DbContext识别数据库视图/表值函数

方式1:Scaffold时直接生成(推荐)

在Package Manager Console执行以下命令,一次性生成包含视图、函数的模型和DbContext:

Scaffold-DbContext "Server=你的服务器名;Database=你的数据库名;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -Views -Functions -Force
  • -Views:生成视图对应的实体类与DbSet
  • -Functions:生成表值函数的映射逻辑
  • -Force:覆盖已存在的模型文件(适用于更新数据库结构后重新生成)

方式2:手动添加到现有DbContext

若已有DbContext,可手动添加视图的DbSet:

public DbSet<ProductView> ProductViews { get; set; }

对于表值函数,手动添加映射方法:

[DbFunction("GetFilteredProducts", Schema = "dbo")]
public IQueryable<Product> GetFilteredProducts(int categoryId)
{
    var param = new SqlParameter("@CategoryId", categoryId);
    return Set<Product>().FromSqlRaw("SELECT * FROM dbo.GetFilteredProducts(@CategoryId)", param);
}

2. 用视图/表值函数填充模型实现CRUD

从视图读取数据(列表页)

直接通过DbContext查询视图获取展示数据:

public IActionResult Index()
{
    var productList = _context.ProductViews.ToList();
    return View(productList);
}

调用表值函数获取筛选数据

根据业务参数调用表值函数,返回筛选后的模型集合:

public IActionResult Filter(int categoryId)
{
    var filteredProducts = _context.GetFilteredProducts(categoryId).ToList();
    return View("Index", filteredProducts);
}

3. 下拉列表:显示标题存储主键

Controller中准备下拉数据源

在Create/Edit页面加载时,将关联表的键值对存入ViewBag:

public IActionResult Create()
{
    // 绑定分类表的Id(存储值)和Name(显示值)
    ViewBag.CategoryId = new SelectList(_context.Categories, "Id", "Name");
    return View();
}

View中渲染下拉列表

用Html.DropDownListFor绑定模型的外键字段,实现“显示标题、提交主键”:

<div class="form-group">
    <label asp-for="CategoryId" class="control-label"></label>
    @Html.DropDownListFor(m => m.CategoryId, ViewBag.CategoryId as SelectList, "请选择分类", new { @class = "form-control" })
    <span asp-validation-for="CategoryId" class="text-danger"></span>
</div>

4. 编辑时调用存储过程/函数

调用存储过程执行编辑操作

在Post请求的Edit方法中,通过ExecuteSqlRaw调用存储过程完成数据更新:

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(int id, [Bind("Id,Name,Price,CategoryId")] Product product)
{
    if (id != product.Id) return NotFound();
    if (!ModelState.IsValid)
    {
        ViewBag.CategoryId = new SelectList(_context.Categories, "Id", "Name", product.CategoryId);
        return View(product);
    }

    try
    {
        var parameters = new[]
        {
            new SqlParameter("@Id", product.Id),
            new SqlParameter("@Name", product.Name),
            new SqlParameter("@Price", product.Price),
            new SqlParameter("@CategoryId", product.CategoryId)
        };
        _context.Database.ExecuteSqlRaw("EXEC dbo.UpdateProduct @Id, @Name, @Price, @CategoryId", parameters);
    }
    catch (DbUpdateException)
    {
        if (!ProductExists(product.Id)) return NotFound();
        throw;
    }
    return RedirectToAction(nameof(Index));
}

调用函数验证编辑权限

编辑前调用自定义函数检查数据合法性:

public IActionResult Edit(int id)
{
    var canEdit = _context.Set<bool>().FromSqlRaw("SELECT dbo.CanEditProduct(@Id)", new SqlParameter("@Id", id)).FirstOrDefault();
    if (!canEdit) return Forbid();

    var product = _context.Products.Find(id);
    ViewBag.CategoryId = new SelectList(_context.Categories, "Id", "Name", product.CategoryId);
    return View(product);
}

注意事项

  • 视图默认只读,编辑操作建议直接针对原表,视图仅用于数据展示
  • 表值函数、存储过程的参数需与数据库定义完全匹配,避免参数不匹配报错
  • 确保DbContext的连接字符串拥有访问视图、函数、存储过程的权限

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 14:53:42