求.NET6+EF Core+OData8下多对多实体的Get/Post控制器示例
.NET6 + EF Core + OData8 多对多关联控制器示例
基于你提供的实体与DbContext配置,以下是针对Company和Category多对多关联的基础控制器实现,包含Get查询、通过$ref添加/删除关联的核心动作:
一、Company控制器核心代码
using Microsoft.AspNetCore.OData; using Microsoft.AspNetCore.OData.Routing.Controllers; using Microsoft.EntityFrameworkCore; using Reviews.Entities; namespace Reviews.Controllers { [Route("odata/Companies")] [ApiController] public class CompaniesController : ODataController { private readonly YourDbContext _context; // 替换为你的实际DbContext类名 public CompaniesController(YourDbContext context) { _context = context; } // 获取单个公司及关联分类(支持$expand查询) [HttpGet("{key}")] [EnableQuery] public async Task<IActionResult> Get([FromRoute] int key) { var company = await _context.Companies .Include(c => c.Categories) .FirstOrDefaultAsync(c => c.CompanyId == key); return company == null ? NotFound() : Ok(company); } // 获取公司的所有关联分类引用($ref集合) [HttpGet("{key}/Categories/$ref")] [EnableQuery] public async Task<IActionResult> GetCategoriesRef([FromRoute] int key) { var company = await _context.Companies .Include(c => c.Categories) .FirstOrDefaultAsync(c => c.CompanyId == key); if (company == null) return NotFound(); var categoryRefs = company.Categories?.Select(c => new { @odata.id = Url.ODataLink(new { controller = "Categories", key = c.CategoryId }) }) ?? Enumerable.Empty<object>(); return Ok(categoryRefs); } // 为公司添加分类关联(通过$ref) [HttpPost("{key}/Categories/$ref")] public async Task<IActionResult> CreateCategoryRef([FromRoute] int key, [FromBody] ODataActionParameters parameters) { if (!parameters.TryGetValue("@odata.id", out var odataId)) { return BadRequest("请求体缺少@odata.id字段"); } var categoryKey = Url.ParseODataId(odataId.ToString())?.LastSegment?.GetKey<int>(); if (categoryKey == null) { return BadRequest("@odata.id格式无效"); } var company = await _context.Companies.Include(c => c.Categories).FirstOrDefaultAsync(c => c.CompanyId == key); var category = await _context.Categories.FindAsync(categoryKey); if (company == null || category == null) return NotFound(); company.Categories ??= new List<Category>(); if (!company.Categories.Any(c => c.CategoryId == category.CategoryId)) { company.Categories.Add(category); await _context.SaveChangesAsync(); } return StatusCode(StatusCodes.Status204NoContent); } // 删除公司与分类的关联(通过$ref) [HttpDelete("{key}/Categories/$ref")] public async Task<IActionResult> DeleteCategoryRef([FromRoute] int key, [FromQuery] string id) { var categoryKey = Url.ParseODataId(id)?.LastSegment?.GetKey<int>(); if (categoryKey == null) { return BadRequest("id查询参数格式无效"); } var company = await _context.Companies.Include(c => c.Categories).FirstOrDefaultAsync(c => c.CompanyId == key); if (company == null) return NotFound(); var categoryToRemove = company.Categories?.FirstOrDefault(c => c.CategoryId == categoryKey); if (categoryToRemove != null) { company.Categories.Remove(categoryToRemove); await _context.SaveChangesAsync(); } return StatusCode(StatusCodes.Status204NoContent); } } }
二、关键配置与操作说明
1. OData端点配置(Program.cs)
确保已启用OData功能并注册实体集:
builder.Services.AddControllers().AddOData(options => { options.Select().Filter().OrderBy().Expand().Count().SetMaxTop(100); options.AddRouteComponents("odata", GetEdmModel()); }); // 构建EDM模型 private static IEdmModel GetEdmModel() { ODataConventionModelBuilder builder = new(); builder.EntitySet<Company>("Companies"); builder.EntitySet<Category>("Categories"); return builder.GetEdmModel(); }
2. $ref操作规范
- 添加关联请求:POST到
odata/Companies/{CompanyId}/Categories/$ref,请求体格式:{"@odata.id": "odata/Categories/{CategoryId}"} - 删除关联请求:DELETE到
odata/Companies/{CompanyId}/Categories/$ref?id=odata/Categories/{CategoryId}
3. EF Core多对多处理
你已通过UsingEntity配置了关联表CompanyCategories,EF Core会自动处理关联数据的插入与删除,无需手动操作关联表。
三、Category控制器简化版
若需对Category执行类似的关联操作,控制器结构与CompaniesController一致,只需替换实体类型:
[Route("odata/Categories")] [ApiController] public class CategoriesController : ODataController { private readonly YourDbContext _context; public CategoriesController(YourDbContext context) { _context = context; } [HttpGet("{key}")] [EnableQuery] public async Task<IActionResult> Get([FromRoute] int key) { var category = await _context.Categories .Include(c => c.Companies) .FirstOrDefaultAsync(c => c.CategoryId == key); return category == null ? NotFound() : Ok(category); } // 关联操作方法与CompaniesController逻辑一致,此处省略 }
内容的提问来源于stack exchange,提问作者leadfollowmove
相关产品推荐
相关产品推荐

