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

仓库模式下如何将Pokemon API数据传入Controller并添加至EF DataContext

问题描述

我创建了一个Web API控制器,用于从公开宝可梦API获取列表并添加到SQL数据库,采用了仓库模式,但遇到了问题:不知道如何将仓库中反序列化的对象传递到控制器并通过DataContext存入数据库。仓库里的HTTP请求、反序列化逻辑没问题,但在Swagger测试时出现类型不兼容的提示,尝试过Stack Overflow上的方案但没成功,求建议。

项目相关代码

PokemonDtoesController.cs

namespace MyPokeAPI.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class PokemonDtoesController : ControllerBase
    {
        private readonly DataContext _context;
        private readonly IPokemonRepository repository;

        public PokemonDtoesController(DataContext context, IPokemonRepository _repository)
        {
            this.repository = _repository;
            _context = context;
        }

        // GET: api/PokemonDtoes
        [HttpGet]
        public async Task<ActionResult<IEnumerable<PokemonDto>>> GetPokemonDto()
        {
            var items = (await repository.GetAllPokemonsAsync());
            _context.Add(items);

            return _context;
        }

        // GET: api/PokemonDtoes/5
        [HttpGet("{id}")]
        public async Task<ActionResult<PokemonDto>> GetPokemonDto(int id)
        {
            var pokemonDto = await _context._pokemons.FindAsync(id);

            if (pokemonDto == null)
            {
                return NotFound();
            }

            return pokemonDto;
        }

        private bool PokemonDtoExists(int id)
        {
            return _context._pokemons.Any(e => e.id == id);
        }
    }
}

PokemonRepository.cs

namespace MyPokeAPI.Repositories
{
    public class PokemonRepository : IPokemonRepository
    {
        private HttpClient _client;
        private PokemonDto currPoke = null;
        private string json = string.Empty;
        int limit = 30;

        private readonly List<PokemonDto> pokemons = new List<PokemonDto>();     

        public async Task<IEnumerable<PokemonDto>> GetAllPokemonsAsync()
        {
            string url = $"https://pokeapi.co/api/v2/pokemon/?offset={limit}&limit={limit}";

            using (_client = new HttpClient())
            {
                _client.BaseAddress = new Uri(url);
                _client.DefaultRequestHeaders.Accept.Clear();
                _client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

                HttpResponseMessage response = await _client.GetAsync(url);

                if (response.IsSuccessStatusCode)
                {
                    json = await response.Content.ReadAsStringAsync();
                    BaseResults myDeserializedClass = JsonConvert.DeserializeObject<BaseResults>(json);

                    if (myDeserializedClass != null)
                    {
                        foreach (var result in myDeserializedClass.results)
                        {
                            using (HttpClient insideclient = new HttpClient())
                            {
                                insideclient.BaseAddress = new Uri(result.url);
                                response = await insideclient.GetAsync(result.url);

                                if (response.IsSuccessStatusCode)
                                {
                                    json = await response.Content.ReadAsStringAsync();
                                    //AbilitiesRoot currPokeAbilities = JsonConvert.DeserializeObject<AbilitiesRoot>(json);
                                    currPoke = JsonConvert.DeserializeObject<PokemonDto>(json);
                                    if (currPoke != null)
                                    {
                                        pokemons.Add(currPoke);
                                    }
                                }
                            }
                        }
                    }
                }
            }

            return pokemons;
        }

        public PokemonDto GetSinglePokemonAsync(string name)
        {
            return pokemons.Where(item => item.name == name).SingleOrDefault();
        }
     }
}

DataContext.cs

namespace MyPokeAPI.Helper
{
    public class DataContext : DbContext
    {
        protected readonly IConfiguration Configuration;

        public DataContext(IConfiguration configuration)
        {
            this.Configuration = configuration;
        }

        protected override void OnConfiguring(DbContextOptionsBuilder options)
        {
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnectionString"));
        }

        public DbSet<PokemonDto> _pokemons { get; set; }        
    }
}
解决方案

1. 修复控制器的Get方法(核心问题)

你的GetPokemonDto方法存在三个关键错误:

  • 用_context.Add(items)添加集合:EF Core的Add方法用于单个实体,集合需要用AddRange
  • 返回_context:方法返回类型是ActionResult<IEnumerable<PokemonDto>>,但你返回了DataContext,类型完全不匹配,这就是Swagger提示类型不兼容的原因
  • 未调用SaveChangesAsync:添加实体后必须保存才能写入数据库

修复后的代码:

[HttpGet]
public async Task<ActionResult<IEnumerable<PokemonDto>>> GetPokemonDto()
{
    var items = await repository.GetAllPokemonsAsync();
    // 用AddRange批量添加集合
    _context._pokemons.AddRange(items);
    // 异步保存到数据库
    await _context.SaveChangesAsync();
    // 返回获取到的宝可梦列表,符合方法返回类型
    return Ok(items);
}

2. 修复仓库的重复数据问题

仓库中pokemons是类级别的私有字段,每次调用GetAllPokemonsAsync都会往同一个列表添加数据,重复调用会导致大量重复实体。应该把列表移到方法内部:

public async Task<IEnumerable<PokemonDto>> GetAllPokemonsAsync()
{
    int limit = 30;
    string url = $"https://pokeapi.co/api/v2/pokemon/?offset={limit}&limit={limit}";
    // 每次调用创建新列表,避免重复数据
    var pokemons = new List<PokemonDto>();

    using (var _client = new HttpClient())
    {
        _client.DefaultRequestHeaders.Accept.Clear();
        _client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

        HttpResponseMessage response = await _client.GetAsync(url);

        if (response.IsSuccessStatusCode)
        {
            var json = await response.Content.ReadAsStringAsync();
            BaseResults myDeserializedClass = JsonConvert.DeserializeObject<BaseResults>(json);

            if (myDeserializedClass != null)
            {
                foreach (var result in myDeserializedClass.results)
                {
                    using (var insideclient = new HttpClient())
                    {
                        response = await insideclient.GetAsync(result.url);

                        if (response.IsSuccessStatusCode)
                        {
                            json = await response.Content.ReadAsStringAsync();
                            var currPoke = JsonConvert.DeserializeObject<PokemonDto>(json);
                            if (currPoke != null)
                            {
                                pokemons.Add(currPoke);
                            }
                        }
                    }
                }
            }
        }
    }

    return pokemons;
}

3. 优化HttpClient使用(可选但推荐)

每次创建新HttpClient会导致socket资源耗尽,建议用IHttpClientFactory注入复用:

  • 修改仓库构造函数:
private readonly HttpClient _client;

public PokemonRepository(HttpClient client)
{
    _client = client;
}
  • 在Program.cs中注册:
builder.Services.AddHttpClient<IPokemonRepository, PokemonRepository>();

4. 验证实体配置

确保PokemonDto类的主键(比如id字段)被EF Core正确识别,可通过数据注解或Fluent API配置:

public class PokemonDto
{
    [Key]
    public int id { get; set; }
    // 其他字段...
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 20:25:30