C# ASP.NET Entity Framework从API提取数组数据并保存的方法
嘿,我来帮你一步步搞定从API提取数据并保存到EF的事儿!结合你已经有Shift类和请求代码的情况,咱们可以这么做:
步骤1:定义API响应模型(确保反序列化正确)
首先得确保你有对应API返回结构的模型类,用来把JSON数据反序列化成C#对象。假设API返回的JSON结构大概是这样:
{ "date": "2024-05-20", "shifts": [ { "id": 1, "name": "早班", "startTime": "08:00", "endTime": "16:00", "employeeCount": 5 }, { "id": 2, "name": "晚班", "startTime": "16:00", "endTime": "24:00", "employeeCount": 3 } ], "costs": [ { "id": 1, "category": "人力", "amount": 1500.00, "shiftId": 1 }, { "id": 2, "category": "物料", "amount": 800.00, "shiftId": 1 } ] }
那对应的C#模型可以这么写(如果你的Shift实体和API返回的结构有差异,建议单独定义DTO来隔离API层和数据层):
// 整个API的响应模型 public class ApiResponse { public DateTime Date { get; set; } public List<ShiftApiDto> Shifts { get; set; } public List<CostApiDto> Costs { get; set; } } // API返回的Shift数据结构(和你的EF Shift实体区分开) public class ShiftApiDto { public int Id { get; set; } public string Name { get; set; } public TimeOnly StartTime { get; set; } public TimeOnly EndTime { get; set; } // 其他API返回的字段,按需保留 } // API返回的Cost数据结构 public class CostApiDto { public int Id { get; set; } public string Category { get; set; } public decimal Amount { get; set; } public int ShiftId { get; set; } }
步骤2:发起API请求并反序列化
用HttpClient发起请求,把返回的JSON反序列化成上面定义的ApiResponse对象:
// 假设这是你的服务类,通过依赖注入拿到HttpClient和EF上下文 public class DataFetchService { private readonly HttpClient _httpClient; private readonly YourDbContext _dbContext; public DataFetchService(HttpClient httpClient, YourDbContext dbContext) { _httpClient = httpClient; _dbContext = dbContext; } public async Task FetchAndProcessDataAsync() { // 替换成你的API地址 var apiResponse = await _httpClient.GetFromJsonAsync<ApiResponse>("https://your-api-endpoint.com/data"); if (apiResponse == null) { throw new InvalidOperationException("API返回的数据为空,请检查请求地址或API状态"); } // 下一步:提取并映射数据到EF实体 await MapAndSaveDataAsync(apiResponse); } }
步骤3:提取并映射数据到EF实体
现在从ApiResponse里提取你需要的字段,映射到EF的实体类(包括你已定义的Shift,如果还没Cost实体可以补充一个):
// 假设你的EF Shift实体已经定义,补充Cost实体(如果需要) public class Cost { public int Id { get; set; } public string Category { get; set; } public decimal Amount { get; set; } public int ShiftId { get; set; } public Shift Shift { get; set; } // 关联Shift实体 } private async Task MapAndSaveDataAsync(ApiResponse apiResponse) { var shiftsToSave = new List<Shift>(); foreach (var shiftDto in apiResponse.Shifts) { // 提取Shift中需要的字段,创建EF Shift实体 var shift = new Shift { Id = shiftDto.Id, Name = shiftDto.Name, StartTime = shiftDto.StartTime, EndTime = shiftDto.EndTime, Date = apiResponse.Date // 把API返回的日期关联到Shift }; // 提取当前Shift对应的Costs数据,过滤并映射到Cost实体 var relatedCosts = apiResponse.Costs .Where(costDto => costDto.ShiftId == shiftDto.Id) .Select(costDto => new Cost { Id = costDto.Id, Category = costDto.Category, Amount = costDto.Amount, ShiftId = shift.Id }) .ToList(); shift.Costs = relatedCosts; shiftsToSave.Add(shift); } // 第四步:保存到数据库 await SaveToDatabaseAsync(shiftsToSave); }
步骤4:保存数据到数据库
最后把映射好的实体保存到EF上下文:
private async Task SaveToDatabaseAsync(List<Shift> shifts) { // 这里可以根据需求选择新增或更新: // 如果是全新数据,用AddRange;如果需要更新已有数据,先查询再判断 foreach (var shift in shifts) { var existingShift = await _dbContext.Shifts.FindAsync(shift.Id); if (existingShift == null) { _dbContext.Shifts.Add(shift); } else { // 更新已有Shift的字段 _dbContext.Entry(existingShift).CurrentValues.SetValues(shift); // 同时更新Costs(这里可以根据需求处理,比如替换或追加) existingShift.Costs.Clear(); existingShift.Costs.AddRange(shift.Costs); } } await _dbContext.SaveChangesAsync(); }
额外注意事项
- DTO隔离:尽量用DTO来处理API返回数据,不要直接把EF实体暴露给API层,避免业务逻辑和数据层耦合。
- 错误处理:记得给API请求、反序列化、数据库操作添加
try-catch块,处理异常情况(比如网络错误、JSON格式错误、数据库约束冲突等)。 - 性能优化:如果API返回的数据量很大,建议分批处理和保存,避免一次性加载太多数据到内存。
- 事务处理:如果需要保证Shift和Cost数据的一致性,可以用EF的事务:
using var transaction = await _dbContext.Database.BeginTransactionAsync(); try { await _dbContext.SaveChangesAsync(); await transaction.CommitAsync(); } catch { await transaction.RollbackAsync(); throw; }
内容的提问来源于stack exchange,提问作者Josh Fletcher
相关产品推荐
相关产品推荐

