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

如何在EF Core+PostgreSQL项目中实现连续cID编号

实现跨批次连续的cID(EF Core + PostgreSQL)

需求说明

每月定时将PostgreSQL数据库中的Institution数据序列化发送到消息队列,要求每次发送的记录拥有跨批次连续的cID:比如第一次发100条用1-100,下月再发这些记录时cID从101开始到200,以此类推。当前代码仅能从1开始编号,需要基于PostgreSQL序列实现连续编号。

现有模型与代码

实体模型

[Table("institutions")]
public partial class Institution
{
    public Institution()
    {
        InstitutionResources = new HashSet<InstitutionResource>();
    }

    [Key]
    [Column("id")]
    public int Id { get; set; }
    public int AddressId { get; set; }
    [Column("phone")]
    [StringLength(20)]
    public string Phone { get; set; }
    [Column("email_address")]
    [StringLength(255)]
    public string EmailAddress { get; set; }
    [ForeignKey(nameof(AddressId))]
    [InverseProperty("Institutions")]
    public virtual Address Address { get; set; }
    [InverseProperty(nameof(InstitutionResource.Institution))]
    public virtual ICollection<InstitutionResource> InstitutionResources { get; set; }
}

当前生成cID的代码

public List<InstitutionDataResult> FormInstitutionDataResult()
{
    long cID = 1; // 这里需要改为跨批次连续的起始值
    var institutions = _dbContext.Institutions
        .Select(s => new InstitutionDataResult
        {
            Id = s.Id,
            NameKk = s.InstitutionResources.Where(l => l.LanguageId == 1).SingleOrDefault().Name,
            NameRu = s.InstitutionResources.Where(l => l.LanguageId == 2).SingleOrDefault().Name,
            Geoposition = s.Address.Geoposition.ToString(),
            Phone = s.Phone,
            Email = s.EmailAddress,
            Date = DateTime.Now.ToString("dd.MM.yyyy")
        }).ToList();
    
    foreach (var institution in institutions)
    {
        institution.CID = cID;
        cID++;
    }
    return institutions; // 原代码中返回crosswalks为笔误,修正为institutions
}

解决方案:使用PostgreSQL序列实现连续编号

步骤1:在PostgreSQL中创建专用序列

执行以下SQL语句,创建一个持久化的序列用于记录cID的当前计数:

-- 创建序列,起始值1,每次递增1
CREATE SEQUENCE cid_sequence
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;

步骤2:修改C#代码实现连续编号逻辑

核心逻辑:每次发送前从数据库获取序列当前值作为起始cID;分配完所有记录的cID后,将序列值更新为「起始cID + 本次发送记录数」,确保下次发送的起始值连续。

修改后的代码:

public List<InstitutionDataResult> FormInstitutionDataResult()
{
    // 1. 获取序列当前值作为起始cID,处理序列刚创建的特殊情况
    long startCid;
    try
    {
        startCid = _dbContext.Database.SqlQuery<long>("SELECT currval('cid_sequence');").FirstOrDefault();
    }
    catch
    {
        // 序列刚创建时currval会报错,先获取nextval再回退到初始值1
        startCid = _dbContext.Database.SqlQuery<long>("SELECT nextval('cid_sequence');").FirstOrDefault();
        _dbContext.Database.ExecuteSqlRaw("SELECT setval('cid_sequence', {0});", startCid - 1);
    }

    var institutions = _dbContext.Institutions
        .Select(s => new InstitutionDataResult
        {
            Id = s.Id,
            NameKk = s.InstitutionResources.Where(l => l.LanguageId == 1).SingleOrDefault()?.Name,
            NameRu = s.InstitutionResources.Where(l => l.LanguageId == 2).SingleOrDefault()?.Name,
            Geoposition = s.Address.Geoposition.ToString(),
            Phone = s.Phone,
            Email = s.EmailAddress,
            Date = DateTime.Now.ToString("dd.MM.yyyy")
        }).ToList();

    // 2. 为每条记录分配连续cID
    long currentCid = startCid;
    foreach (var institution in institutions)
    {
        institution.CID = currentCid;
        currentCid++;
    }

    // 3. 更新序列值,保证下次起始值连续
    _dbContext.Database.ExecuteSqlRaw("SELECT setval('cid_sequence', {0});", currentCid);

    return institutions;
}

关键补充

  • 原子性保障:PostgreSQL序列本身是原子性操作,多并发请求也不会出现重复或跳号问题。
  • 异常回滚:如果发送过程中出现异常,需要用事务包裹整个流程,回滚序列值避免计数断层:
using var transaction = _dbContext.Database.BeginTransaction();
try
{
    // 上述获取起始cID、分配cID、更新序列的代码
    transaction.Commit();
}
catch (Exception ex)
{
    transaction.Rollback();
    // 处理异常逻辑
    throw;
}
  • 持久化特性:序列值存储在数据库中,服务或数据库重启后不会丢失计数,确保跨批次的连续性。

内容的提问来源于stack exchange,提问作者Мади Маликов

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 22:57:45