使用Max+1创建用户友好的唯一序列号的替代方案



我的asp.net mvc web应用程序中有一个存储库方法,可以自动生成一个名为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

  1. 我还可以采用哪些方法来获得一个始终唯一的序列号。

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

谢谢你的帮助。

这个问题的一个完整解决方案是将自动递增列和计算列的使用结合起来。

桌子看起来像这样:

CREATE TABLE [dbo].[somedata](
    [id] [bigint] IDENTITY(1,1) NOT NULL,
    [reference] [varchar](50) NULL,
    [STag]  AS ('S'+CONVERT([varchar](19),[id],(0))),
    CONSTRAINT [PK_somedata] PRIMARY KEY CLUSTERED ([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);
    }
}

如果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确保只有当其值在获取记录和更新记录之间没有变化时才允许更新。

最新更新