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

.NET Web API仓储模式下,如何通过分类名添加带关联实体的商品

问题描述

当前添加商品时需要传入CategoryId才能关联分类,希望改为仅传入CategoryName即可完成关联,无需提供CategoryId,请问如何修改Post方法实现该需求?


提供的代码实现

Product实体

public class Product : BaseEntity
{
   public string ProductName { get; set; }
   public string Description { get; set; }
   public string Img1 { get; set; }
   public string Img2 { get; set; }
   public string Img3 { get; set; }
   public decimal Price { get; set; }
   public int Stock { get; set; }

   // 关联实体
   public Category Category { get; set; }
   public int CategoryId { get; set; }
}

Category实体

public class Category : BaseEntity
{
    public string Name { get; set; }
    public string Img { get; set; }
    public string Description { get; set; }
}

IProductRepository接口

public interface IProductRepository
{
    Task<Product> GetProductByIdAsync(int id);
    Task<IReadOnlyList<Product>> GetProductsAsync();
    Task<bool> SaveChangesAsync();
    void Add(Product product);
    void Update(Product product);
    void Delete(Product product);
}

Product仓储实现

namespace Infrastructure
{
    public class ProductRepository : IProductRepository
    {
       private readonly StoreContext _context;

        public ProductRepository(StoreContext context)
        {
            _context = context;
        }

        public void Add(Product product)
        {
            _context.Add(product);
        }

        public void Delete(Product product)
        {
            _context.Remove(product);
        }

        public async Task<Product> GetProductByIdAsync(int id)
        {
            return await _context.Products.Include(c => c.Category)
            .FirstOrDefaultAsync(p => p.Id == id);
        }

        public async Task<IReadOnlyList<Product>> GetProductsAsync()
        {
            return await _context.Products.Include(p => p.Category).
            ToArrayAsync();
        }

        public async Task<bool> SaveChangesAsync()
        {
            return await _context.SaveChangesAsync().ConfigureAwait(false) > 0;
        }

        public void Update(Product product)
        {
            _context.Attach(product);
            _context.Entry(product).State = EntityState.Modified;
        }
    }
}

原ProductController的Post方法

[HttpPost]
public async Task<ActionResult> AddProduct(Product product)
{
    try
    {
        if (product.Id == 0)
        {
            var responseError = new ResponseError(StatusCodes.Status400BadRequest, "Fields cannot be empty.");
            var response = new Response(false, null, responseError);
            return BadRequest(response);
        }
        else
        {
            _repository.Add(product);
            await _repository.SaveChangesAsync();
            var response = new Response(true, product, null);
            return Ok(response);
        }

    }
    catch (Exception e)
    {
        var responseError = new ResponseError(StatusCodes.Status500InternalServerError, e.Message);
        var response = new Response(false, null, responseError);
        return StatusCode(StatusCodes.Status500InternalServerError, response);
    }
}

解决方案

步骤1:创建新增商品的DTO

不要直接用Product实体接收前端请求,创建专门的DTO来接收参数,包含业务字段和CategoryName:

public class AddProductDto
{
    public string ProductName { get; set; }
    public string Description { get; set; }
    public string Img1 { get; set; }
    public string Img2 { get; set; }
    public string Img3 { get; set; }
    public decimal Price { get; set; }
    public int Stock { get; set; }
    public string CategoryName { get; set; } // 接收分类名称
}

步骤2:修改Post方法逻辑

替换方法参数为AddProductDto,根据分类名称查询对应分类,处理关联逻辑,同时修复原方法的错误判断:

[HttpPost]
public async Task<ActionResult> AddProduct(AddProductDto productDto)
{
    try
    {
        // 验证必填业务字段
        if (string.IsNullOrWhiteSpace(productDto.ProductName) || productDto.Price <= 0)
        {
            var responseError = new ResponseError(StatusCodes.Status400BadRequest, "必填字段不能为空或格式错误.");
            var response = new Response(false, null, responseError);
            return BadRequest(response);
        }

        // 根据分类名称查询对应的Category(忽略大小写匹配)
        var category = await _context.Categories.FirstOrDefaultAsync(c => 
            c.Name.Equals(productDto.CategoryName, StringComparison.OrdinalIgnoreCase));
        
        if (category == null)
        {
            var responseError = new ResponseError(StatusCodes.Status404NotFound, $"不存在名称为{productDto.CategoryName}的分类.");
            var response = new Response(false, null, responseError);
            return NotFound(response);
        }

        // 构建Product实体并关联分类ID
        var product = new Product
        {
            ProductName = productDto.ProductName,
            Description = productDto.Description,
            Img1 = productDto.Img1,
            Img2 = productDto.Img2,
            Img3 = productDto.Img3,
            Price = productDto.Price,
            Stock = productDto.Stock,
            CategoryId = category.Id
        };

        _repository.Add(product);
        await _repository.SaveChangesAsync();

        var response = new Response(true, product, null);
        return Ok(response);

    }
    catch (Exception e)
    {
        var responseError = new ResponseError(StatusCodes.Status500InternalServerError, e.Message);
        var response = new Response(false, null, responseError);
        return StatusCode(StatusCodes.Status500InternalServerError, response);
    }
}

步骤3:仓储扩展(可选)

如果希望将分类查询逻辑封装到仓储,给IProductRepository添加方法:

// IProductRepository接口新增
Task<Category> GetCategoryByNameAsync(string categoryName);

仓储实现中添加对应方法:

public async Task<Category> GetCategoryByNameAsync(string categoryName)
{
    return await _context.Categories.FirstOrDefaultAsync(c => 
        c.Name.Equals(categoryName, StringComparison.OrdinalIgnoreCase));
}

之后控制器可调用_repository.GetCategoryByNameAsync(productDto.CategoryName)查询分类,遵循仓储模式的职责分离。

关键说明

  1. 原方法中product.Id ==0的判断逻辑错误,新增商品时Id通常为自增默认值0,应验证实际必填的业务字段。
  2. 使用StringComparison.OrdinalIgnoreCase忽略大小写匹配分类名称,提升用户体验。
  3. 必须处理分类不存在的情况,返回404错误,避免因无效CategoryId导致数据库异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 11:15:38