You need to enable JavaScript to run this app. 在.NET Core中创建含两个外键的模型类与控制器(Assign中间表开发)
优惠活动
大模型
产品
解决方案
定价
更多

在.NET Core中创建含两个外键的模型类与控制器(Assign中间表开发)

适配现有手写SQL风格的多对多关联实现方案

1. 新增Assign中间表模型类

完全对齐你现有Consultant、Project模型的简洁POCO风格,不需要硬套EF Core导航属性,直接定义对应字段即可:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace WebAPI_C5.Models
{
    public class Assign
    {
        // 自增主键,方便CRUD操作定位单条记录
        public int AssignId { get; set; }
        // 关联Consultant表的外键字段
        public int ConsultantId { get; set; }
        // 关联Project表的外键字段
        public int ProjectId { get; set; }
    }
}

对应的数据库中间表建表参考SQL:

CREATE TABLE dbo.Assign(
    AssignId int PRIMARY KEY IDENTITY(1,1),
    ConsultantId int NOT NULL,
    ProjectId int NOT NULL,
    -- 外键参照约束,保证关联数据完整性
    FOREIGN KEY (ConsultantId) REFERENCES dbo.Consultant(ConsultantId),
    FOREIGN KEY (ProjectId) REFERENCES dbo.Project(ProjectId),
    -- 唯一约束,避免同一顾问重复绑定到同一项目
    CONSTRAINT UQ_Assign_Consultant_Project UNIQUE(ConsultantId, ProjectId)
)

2. 新增AssignController控制器

完全沿用你现有ConsultantController的编码模式,通过依赖注入读取连接字符串,手写SQL完成CRUD操作,同时修正你原有代码直接拼接SQL的SQL注入问题,代码如下:

using Microsoft.AspNetCore.Mvc;
using System.Data;
using System.Data.SqlClient;

namespace WebAPI_C5.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class AssignController : ControllerBase
    {
        private readonly IConfiguration _configuration;
        public AssignController(IConfiguration configuration)
        {
            _configuration = configuration;
        }

        // 获取全部分配关联,联表返回关联的顾问、项目名称
        [HttpGet]
        public JsonResult Get()
        {
            string query = @"
                SELECT a.AssignId, a.ConsultantId, c.ConsultantName, a.ProjectId, p.ProjectName 
                FROM dbo.Assign a
                LEFT JOIN dbo.Consultant c ON a.ConsultantId = c.ConsultantId
                LEFT JOIN dbo.Project p ON a.ProjectId = p.ProjectId
            ";
            DataTable table = new DataTable();
            string sqlDataSource = _configuration.GetConnectionString("ProjectAppCon");
            using (SqlConnection myCon = new SqlConnection(sqlDataSource))
            {
                myCon.Open();
                using (SqlCommand myCommand = new SqlCommand(query, myCon))
                {
                    SqlDataReader myReader = myCommand.ExecuteReader();
                    table.Load(myReader);
                }
            }
            return new JsonResult(table);
        }

        // 新增绑定:将顾问和项目关联起来
        [HttpPost]
        public JsonResult Post(Assign assign)
        {
            // 使用参数化查询替代字符串拼接,避免SQL注入
            string query = @"
                INSERT INTO dbo.Assign (ConsultantId, ProjectId)
                VALUES (@ConsultantId, @ProjectId)
            ";
            string sqlDataSource = _configuration.GetConnectionString("ProjectAppCon");
            using (SqlConnection myCon = new SqlConnection(sqlDataSource))
            {
                myCon.Open();
                using (SqlCommand myCommand = new SqlCommand(query, myCon))
                {
                    myCommand.Parameters.AddWithValue("@ConsultantId", assign.ConsultantId);
                    myCommand.Parameters.AddWithValue("@ProjectId", assign.ProjectId);
                    myCommand.ExecuteNonQuery();
                }
            }
            return new JsonResult("分配关系添加成功");
        }

        // 更新绑定:调整某条关联记录对应的顾问或项目
        [HttpPut]
        public JsonResult Put(Assign assign)
        {
            string query = @"
                UPDATE dbo.Assign 
                SET ConsultantId = @ConsultantId, ProjectId = @ProjectId
                WHERE AssignId = @AssignId
            ";
            string sqlDataSource = _configuration.GetConnectionString("ProjectAppCon");
            using (SqlConnection myCon = new SqlConnection(sqlDataSource))
            {
                myCon.Open();
                using (SqlCommand myCommand = new SqlCommand(query, myCon))
                {
                    myCommand.Parameters.AddWithValue("@AssignId", assign.AssignId);
                    myCommand.Parameters.AddWithValue("@ConsultantId", assign.ConsultantId);
                    myCommand.Parameters.AddWithValue("@ProjectId", assign.ProjectId);
                    myCommand.ExecuteNonQuery();
                }
            }
            return new JsonResult("分配关系更新成功");
        }

        // 删除绑定:解除顾问和项目的关联
        [HttpDelete("{id}")]
        public JsonResult Delete(int id)
        {
            string query = @"
                DELETE FROM dbo.Assign WHERE AssignId = @AssignId
            ";
            string sqlDataSource = _configuration.GetConnectionString("ProjectAppCon");
            using (SqlConnection myCon = new SqlConnection(sqlDataSource))
            {
                myCon.Open();
                using (SqlCommand myCommand = new SqlCommand(query, myCon))
                {
                    myCommand.Parameters.AddWithValue("@AssignId", id);
                    myCommand.ExecuteNonQuery();
                }
            }
            return new JsonResult("分配关系删除成功");
        }
    }
}

3. 后续使用说明

  • 你原有ConsultantController、ProjectController中直接拼接SQL字符串的写法存在SQL注入风险,后续可以参照上面的参数化写法逐步替换原有拼接逻辑,不需要大改现有代码结构
  • 要查询某项目下的所有关联顾问、或某顾问参与的所有项目,直接通过Assign表做关联查询即可,不需要写复杂的跨表逻辑,比如查询某顾问参与的项目:
    SELECT p.* FROM dbo.Project p 
    INNER JOIN dbo.Assign a ON p.ProjectId = a.ProjectId 
    WHERE a.ConsultantId = @传入的顾问ID
    
  • 中间表的唯一约束可以从数据库层面避免重复绑定的无效数据,不需要在后端写额外的判重逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.10 11:36:05