所有文章 > 如何集成API > C# .NET Core API 创建方法详解|Entity Framework 多对多关系实战
C# .NET Core API 创建方法详解|Entity Framework 多对多关系实战

C# .NET Core API 创建方法详解|Entity Framework 多对多关系实战

1. 引言

在实际项目中,API 的 Create 操作往往不仅仅是简单地插入一条记录,而需要同时处理实体之间的多对多、多对一关系。本文以“宝可梦(Pokemon)”示例,演示如何通过 Repository 模式和 Entity Framework Core,优雅地实现复杂的 Create 方法,并在 Controller 层提供清晰、易用的 POST 接口。

核心收益

  • 掌握 Repository 模式下 Create 方法的编写流程
  • 理解 EF Core 多对多关系的插入机制
  • 优化 API 参数传递,提升接口可读性

2. 前置条件与项目结构

  • 技术栈:.NET Core 6+、C#、Entity Framework Core

  • 项目结构(示例):

    /Interfaces
    IPokemonRepository.cs
    ICategoryRepository.cs
    /Repositories
    PokemonRepository.cs
    CategoryRepository.cs
    /Controllers
    PokemonController.cs
    /DTOs
    PokemonCreateDto.cs
    /Mappings
    MappingProfile.cs
  • 已配置好数据库上下文 AppDbContext,包含 PokemonsOwnersCategories 及对应的 Join 表 PokemonOwnersPokemonCategories


3. 接口(Interface):蓝图设计

在 Repository 模式中,接口定义了对外的方法约定。以 IPokemonRepository 为例:

public interface IPokemonRepository
{
    bool CreatePokemon(int ownerId, int categoryId, Pokemon pokemon);
    bool Save(); // 返回布尔值,指示保存成功与否
    // … 其他方法如 Update、Delete、Get 等
}

要点:始终先定义接口,再在具体类中实现。接口扮演“蓝图”角色,有助于解耦与测试。

4. Repository 中的 Create 方法实现

4.1 处理多对多关系的数据预加载

由于 PokemonOwnerCategory 之间是多对多关系,插入新 Pokemon 时,必须先从数据库中获取对应的 OwnerCategory 实体:

var owner = _context.Owners.FirstOrDefault(o => o.Id == ownerId);
var category = _context.Categories.FirstOrDefault(c => c.Id == categoryId);

4.2 构造关联实体并添加到 Join 表

接着,通过构造中间表实体,将它们与主实体关联,并添加到相应的 DbSet:

var pokemonOwner = new PokemonOwner {
    Owner    = owner,
    Pokemon  = pokemon
};
var pokemonCategory = new PokemonCategory {
    Category = category,
    Pokemon  = pokemon
};

_context.PokemonOwners.Add(pokemonOwner);
_context.PokemonCategories.Add(pokemonCategory);

注意:若直接使用 AutoMapper 映射,逻辑会较为隐晦,这里手动创建对象更清晰易懂。

4.3 返回布尔值与统一保存逻辑

最后,执行保存并返回结果:

public bool CreatePokemon(int ownerId, int categoryId, Pokemon pokemon)
{
    // … 上述预加载与关联构造
    _context.Pokemons.Add(pokemon);
    return Save();
}

public bool Save()
{
    // 建议改为 >0 更严谨:return _context.SaveChanges() > 0;
    return _context.SaveChanges() >= 0;
}


5. Controller 中的 POST 接口设计

5.1 从 Query 而非 Body 传参的优势

为了让接口更加简洁易读,可将关联实体的 Id(如 ownerIdcategoryId)通过 URL Query 传递,而将主要数据通过 Body 传输:

[HttpPost]
public IActionResult CreatePokemon(
    [FromQuery] int ownerId,
    [FromQuery] int categoryId,
    [FromBody] PokemonCreateDto dto)
{
    var pokemon = _mapper.Map < Pokemon > (dto);
    if (!_pokemonRepo.CreatePokemon(ownerId, categoryId, pokemon))
        return BadRequest("创建失败");
    return NoContent(); // HTTP 204
}

5.2 DTO 与 AutoMapper 映射配置

定义精简的 DTO,避免过度暴露数据库结构:

public class PokemonCreateDto
{
    public string Name     { get; set; }
    public string ImageUrl { get; set; }
    // … 其他必要字段
}

MappingProfile 中添加映射规则:

CreateMap < PokemonCreateDto, Pokemon > ();

AutoMapper 会自动将 DTO 字段映射到实体,前提是名称一致或已在 Profile 中自定义。


6. 测试与调试

  1. 使用 Swagger UI 或 Postman 发起 POST 请求:

    POST /api/pokemons?ownerId=1&categoryId=2
    Body: { "name": "Mew", "imageUrl": "…" }
  2. 确认 HTTP 204 返回,无 Content:

  1. 检查数据库中 PokemonsPokemonOwnersPokemonCategories 表,验证数据是否正确插入。

7. 小结与最佳实践

  • 接口优先:先定义接口,再实现逻辑,便于解耦与测试。
  • 手动关联:多对多关系插入时,手动构造中间表实体更直观。
  • 参数传递:关键 Id 放在 Query,主体数据放在 Body,接口更简洁。
  • 统一保存:通过 Save() 方法统一提交并返回布尔结果,提高可维护性。
  • DTO 隐藏:使用 DTO 限制暴露字段,配合 AutoMapper 映射。
  • 完整测试:结合 Include、Swagger、Postman 等工具,确保插入与查询一致性。

通过以上步骤,您已掌握在 .NET Core 中使用 Entity Framework Core 实现复杂 Create API 的核心方法,并能编写出结构清晰、性能可控、易于维护的 RESTful 接口。
希望这篇教程能助您在 API 开发道路上走得更稳、更远!

原文引自YouTube视频:https://www.youtube.com/watch?v=j0-cnsCZf7g

#你可能也喜欢这些API文章!

我们有何不同?

API服务商零注册

多API并行试用

数据驱动选型,提升决策效率

查看全部API→
🔥

热门场景实测,选对API

#AI文本生成大模型API

对比大模型API的内容创意新颖性、情感共鸣力、商业转化潜力

25个渠道
一键对比试用API 限时免费

#AI深度推理大模型API

对比大模型API的逻辑推理准确性、分析深度、可视化建议合理性

10个渠道
一键对比试用API 限时免费