C# 使用Max+;1创建用户友好的唯一序列号

C# 使用Max+;1创建用户友好的唯一序列号,c#,asp.net,entity-framework,asp.net-mvc-4,sql-server-2008-r2,C#,Asp.net,Entity Framework,Asp.net Mvc 4,Sql Server 2008 R2,我的asp.net mvc web应用程序中有repository方法,可以自动生成一个名为Tag的唯一序列号:- public void InsertOrUpdateServer(TMSServer server, string username) { if (server.TMSServerID == default(int)) { // New entity int technologyypeID =

我的asp.net mvc web应用程序中有repository方法,可以自动生成一个名为Tag的唯一序列号:-

public void InsertOrUpdateServer(TMSServer server, string username)
        {

    if (server.TMSServerID == default(int))
            {
                // New entity
    int technologyypeID = GetTechnologyTypeID("Server");
    Technology technology = new Technology
       {
     IsDeleted = true,
     Tag = "S" + GetTagMaximumeNumber(technologyypeID).ToString(),
     StartDate = DateTime.Now,
     };
   Save();
//code goes here
其中GetTagMaximumeNumber()函数为:-

public int GetTagMaximumeNumber(int typeID) {
string s = tms.Technologies.Where(a => a.TypeID == typeID).Max(a2 => a2.Tag.Substring(1));

           if (s != null)
           {
             return Int32.Parse(s) + 1;

           }
           else {
               return 100;//if this is the first record created
           }}
上面将获得标记的最大数量,并添加1,然后尝试将其保存到数据库中。上述方法运行良好,但我确信,在多个用户将添加记录的生产服务器上,当尝试添加数据库中已经存在的自动生成的标记号时,将生成相同的标记号,并引发异常。 因此,我有以下问题:-1

  • 我可以遵循哪些其他方法来获得始终唯一的序列号

  • 在我目前的方法中,标签号的间隔是最小的。只有当用户删除记录且其标记号不是最大值时,才会出现间隙。那么,在任何新的方法中,有没有一种方法可以保持这种状态,从而使差距最小化


  • 感谢您的帮助。

    此问题的完整解决方案是结合使用自动递增列和计算列

    该表的外观如下所示:

    创建表[dbo].[somedata](
    [id][bigint]标识(1,1)不为空,
    [reference][varchar](50)空,
    [STag]AS('S'+转换([varchar](19),[id],(0)),
    约束[PK_somedata]主键群集([id]ASC)
    )   
    
    使用映射:

    public class SomeDataMap : EntityTypeConfiguration<SomeData>
    {
        public SomeDataMap()
        {
            // Primary Key
            this.HasKey(t => t.id);
    
            // Properties
            this.Property(t => t.id)
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    
            this.Property(t => t.reference)
                .HasMaxLength(50);
    
            this.Property(t => t.STag)
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);
        }
    }
    
    public类SomeDataMap:EntityTypeConfiguration
    {
    公共数据映射()
    {
    //主键
    this.HasKey(t=>t.id);
    //性质
    this.Property(t=>t.id)
    .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    this.Property(t=>t.reference)
    .HasMaxLength(50);
    this.Property(t=>t.STag)
    .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);
    }
    }
    
    如果SQL 2012中的新序列不是一个选项(因为您无法升级),您可以创建一个存储最后序列号的表

    在EF上下文中,表示类如下所示

    class TaggedSequence
    {
        [Key]
        public int Id { get; set; }
    
        [Required]
        public int Last { get; set; }
    
        [Required]
        [Column(TypeName = "CHAR"), StringLength(1)]
        public string Tag { get; set; }
    
        [Timestamp]
        public byte[] Rowversion { get; set; }
    }
    
    以及使用它的裸骨程序:

    using (var context = new MyContext())
    {
        try
        {
            var tag = "S";
            var sequence = context.TaggedSequence.Single(s => s.Tag == tag);
            sequence.Last += 1;
            Technology technology = new Technology { ... };
            technology.Id = tag + sequence.Last;
            context.Technologies.Add(technology);
            context.SaveChanges();
        }
        catch (DbUpdateConcurrencyException ex)
        {
            // Retry
        }
    }
    
    (您必须将其放入存储库对象中)


    并发检查用于防止并发用户绘制相同的编号。
    Rowversion
    确保仅当其值在获取记录和更新记录之间没有变化时才允许进行更新。

    当然可以使用,如果某项操作删除了一行中的最大值,那么您最终(在两个不同的时间点)拥有两个具有相同标记的实体。这可能是个问题,也可能不是,但值得记住。@amdixon auto increment在我的情况下不起作用,因为我的标签号前面有字符串前缀。因此,我可能有两个具有相同整数的标记,但它们的第一个字符串不同,例如S100和R100。因此,出于这个原因,我没有使用自动递增。也许您可以将字段拆分为
    tech\u type
    [例如
    'S'
    ]和
    tag\u id
    作为自动递增整数,以便使用标准递增序列如果使用sql 2012是一个选项,您可以使用CREATE Sequences感谢您的回复,但这在我的情况下不起作用,正如我前面提到的,一些标记将以“S”other和“R”other和“SO”开头,等等,这取决于techType@JohnJohn您可以根据其他值更改规则以使用不同的前缀。只是想找出一些方法来节省额外的读取或遍历数据库。那么你的意思是我应该提前用序列号填充TaggedSequence表吗?是的,你是对的。忘了提那件事了。那将是一次性操作。但我从未遇到过这样的实现,,你觉得这样做对吗?我甚至在一个应用程序中使用过类似的东西!