.NET 6控制台EF Core调用SaveChanges()后数据库未更新求助
.NET 6控制台应用EF Core批量更新数据库无变化问题排查与解决
问题描述
在.NET 6控制台应用中,通过Foreach循环更新SQL Server中约900条数据,执行完成后数据库无任何更新。调试时API调用正常,所有变量及要更新的item.Status值均正确,但调用SaveChanges()后数据库未发生变化。
相关代码如下:
主逻辑代码
Excel_DBContext context = new Excel_DBContext(); var excel = context.Sheets.Where(c => c.Status == null).ToList(); CallWebAPIAsync().Wait(); async Task CallWebAPIAsync() { using (var client = new HttpClient()) { client.BaseAddress = new Uri("https://jamservice.pna.co.ir/"); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); Parameters countryList; string terminalId; string serial; HttpResponseMessage response; foreach (var item in excel) { terminalId = item.Terminal; serial = item.Serial; countryList = new Parameters() { TerminalID = terminalId, Serials = serial }; response = await client.PostAsJsonAsync("services/api/RequestService/BindSerialToSwitch", countryList); var resultString = await response.Content.ReadAsStringAsync(); var resultJson = JsonConvert.DeserializeObject<Excel>(resultString); Sheet findTerminal = context.Sheets.First(c => c.Terminal == terminalId); if (response.IsSuccessStatusCode) { item.Status = resultJson.StatusTitle; context.SaveChanges(); Console.WriteLine("Record " + terminalId + " updated"); } else { Console.WriteLine("Error"); } } } }
Sheet实体类
public partial class Sheet { public string? Terminal { get; set; } public string? Serial { get; set; } public string? Model { get; set; } public string? Status { get; set; } }
API响应对应类
public class Excel { public string? Terminal { get; set; } public string? Serial { get; set; } public string? StatusTitle { get; set; } }
问题原因分析
- Sheet实体缺少主键:EF Core需要主键来唯一标识实体,否则无法跟踪实体变化并生成正确的Update语句。当前
Sheet类未定义主键,导致SaveChanges()无法识别要更新的记录。 - 异步调用方式不当:使用
.Wait()阻塞异步方法可能导致上下文状态异常,影响EF Core的实体跟踪逻辑。 - 未捕获
SaveChanges()异常:若SaveChanges()执行时抛出异常(如数据约束冲突),未被捕获会导致更新失败但无报错提示。
解决方案
1. 为Sheet实体添加主键
EF Core必须依赖主键来管理实体,可通过两种方式配置:
方式一:通过DataAnnotations特性标记
using System.ComponentModel.DataAnnotations; public partial class Sheet { [Key] // 标记Terminal为主键(需确保Terminal字段值唯一) public string? Terminal { get; set; } public string? Serial { get; set; } public string? Model { get; set; } public string? Status { get; set; } }
方式二:通过Fluent API配置
在Excel_DBContext的OnModelCreating方法中配置主键:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Sheet>().HasKey(s => s.Terminal); }
2. 修复异步调用方式
将控制台应用的Main方法改为异步,使用await替代.Wait(),避免上下文状态异常:
static async Task Main(string[] args) { using var context = new Excel_DBContext(); // 使用using确保上下文正确释放 var excel = context.Sheets.Where(c => c.Status == null).ToList(); await CallWebAPIAsync(context, excel); } async Task CallWebAPIAsync(Excel_DBContext context, List<Sheet> excel) { using (var client = new HttpClient()) { client.BaseAddress = new Uri("https://jamservice.pna.co.ir/"); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); foreach (var item in excel) { var terminalId = item.Terminal; var serial = item.Serial; var countryList = new Parameters() { TerminalID = terminalId, Serials = serial }; var response = await client.PostAsJsonAsync("services/api/RequestService/BindSerialToSwitch", countryList); var resultString = await response.Content.ReadAsStringAsync(); var resultJson = JsonConvert.DeserializeObject<Excel>(resultString); if (response.IsSuccessStatusCode) { item.Status = resultJson.StatusTitle; try { int affectedRows = context.SaveChanges(); Console.WriteLine($"Record {terminalId} updated, affected rows: {affectedRows}"); } catch (Exception ex) { Console.WriteLine($"Failed to update {terminalId}: {ex.Message}"); } } else { Console.WriteLine($"API call failed for {terminalId}"); } } } }
3. 移除多余的实体查询
代码中Sheet findTerminal = context.Sheets.First(c => c.Terminal == terminalId);属于冗余代码,item已经是被上下文跟踪的实体,直接更新item.Status即可,无需重复查询。
4. 添加异常捕获
在SaveChanges()处添加异常捕获,便于排查更新失败的具体原因。
内容的提问来源于stack exchange,提问作者Ali Jebali
相关产品推荐
相关产品推荐

