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

字典实现客户ID自动生成时MySQL主键重复异常排查

问题原因分析

咱们先拆解下你遇到的问题:抛出的Duplicate entry '0' for key 'customer.PRIMARY'异常已经很明确——你插入的Id_Cus值是0,而这个主键值已经在数据库里存在了。具体问题出在这两处:

  • 新客户的Id_Cus未被赋值:你注释掉了从customerDataContract获取Id_Cus的代码,但也没通过其他逻辑给新创建的cust对象的Id_Cus设置唯一值,所以它默认是0。第一次插入时数据库里还没有0这个主键,所以成功了;第二次插入时Id_Cus还是0,直接触发主键重复的冲突。
  • 你写的字典逻辑完全没发挥作用:你查询了已有邮箱对应的Id_Cus并存入字典,但后续根本没用到这个字典——既没检查新客户的邮箱是否已存在(复用已有Id),也没根据邮箱生成新的唯一Id,这段代码属于冗余代码。
解决方案

根据你“借助字典根据输入邮箱自动生成Id_Cus”的需求,分两种常见场景给你解决思路:

场景1:邮箱已存在则复用Id,不存在则生成新唯一Id

如果你的业务是同一个邮箱对应同一个客户,那可以先查询邮箱是否存在,再决定是复用还是新建:

public void InsertCustomer(customer customerDataContract) {
    // 先查询当前邮箱是否已有对应的客户
    var existingCustomer = dc.customers.FirstOrDefault(x => x.Email_Cus == customerDataContract.Email_Cus);
    
    customer cust;
    if (existingCustomer != null) {
        // 邮箱已存在,复用已有Id,可选更新客户其他信息
        cust = existingCustomer;
        cust.FirstName_Cus = customerDataContract.FirstName_Cus;
        cust.LastName_Cus = customerDataContract.LastName_Cus;
        cust.PhoneNum_Cus = Convert.ToInt32(customerDataContract.PhoneNum_Cus);
    } else {
        // 邮箱不存在,创建新客户并生成唯一Id
        cust = new customer();
        cust.FirstName_Cus = customerDataContract.FirstName_Cus;
        cust.LastName_Cus = customerDataContract.LastName_Cus;
        cust.PhoneNum_Cus = Convert.ToInt32(customerDataContract.PhoneNum_Cus);
        cust.Email_Cus = customerDataContract.Email_Cus;
        
        // 生成唯一Id:取现有最大Id加1(如果是并发场景建议用数据库自增,这里是简单示例)
        int maxExistingId = dc.customers.Any() ? dc.customers.Max(x => x.Id_Cus) : 0;
        cust.Id_Cus = maxExistingId + 1;
    }
    
    // 新客户才需要添加到上下文,现有客户EF会自动跟踪变更
    if (existingCustomer == null) {
        dc.customers.Add(cust);
    }
    
    dc.SaveChanges();
    
    // 后续查询逻辑保留
    customer custFromDb = dc.customers.Include(c => c.customerpreference)
                                     .Include(c => c.orders)
                                     .Include(c => c.dishesrankings)
                                     .First(n => n.Id_Cus == cust.Id_Cus);
}

场景2:把Id_Cus设为自增主键(更推荐的生产级做法)

如果你的业务允许Id_Cus是无意义的唯一标识,那直接把数据库的Id_Cus字段设为AUTO_INCREMENT(MySQL),同时在EF模型里标记为自增,这样根本不需要手动赋值:

  1. 数据库端:修改customer表的Id_Cus列,设置为PRIMARY KEY AUTO_INCREMENT
  2. EF模型端:给Id_Cus字段添加特性(或者用Fluent API配置):
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id_Cus { get; set; }
    
  3. 简化后的插入代码:
    public void InsertCustomer(customer customerDataContract) {
        customer cust = new customer();
        cust.FirstName_Cus = customerDataContract.FirstName_Cus;
        cust.LastName_Cus = customerDataContract.LastName_Cus;
        cust.PhoneNum_Cus = Convert.ToInt32(customerDataContract.PhoneNum_Cus);
        cust.Email_Cus = customerDataContract.Email_Cus;
        
        dc.customers.Add(cust);
        dc.SaveChanges(); // 保存后,EF会自动把数据库生成的自增Id赋值给cust.Id_Cus
        
        customer custFromDb = dc.customers.Include(c => c.customerpreference)
                                         .Include(c => c.orders)
                                         .Include(c => c.dishesrankings)
                                         .First(n => n.Id_Cus == cust.Id_Cus);
    }
    

这种方式能避免手动生成Id时的并发冲突,可靠性更高。

额外提示
  • 原代码里的字典逻辑完全没被使用,可以直接删除。
  • 用Convert.ToInt32处理电话号码要谨慎:如果输入的号码包含非数字字符(比如+86、-)会抛出转换异常,建议改用字符串类型存储电话号码(更合理,因为电话号码一般不需要数值运算)。

内容的提问来源于stack exchange,提问作者Кирилл Филободченко

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 12:28:16