C# 复杂主键中Max(ID)的替代项

C# 复杂主键中Max(ID)的替代项,c#,database,nhibernate,primary-key,C#,Database,Nhibernate,Primary Key,我正在制作一个发票系统,支持多个子公司,每个子公司都有自己的发票号码集,因此我有一个主键为(Subsidiary,InvoiceNo)的表 我不能使用MySQL自动递增字段,因为它将不断递增所有子数据的相同计数 我不想为每个子公司制作单独的表格,因为需要时会添加新的子公司 我目前正在使用表中的“选择最大(ID),其中子公司=X”,并根据此添加发票 我使用的是nHibernate,发票插入在InvoiceItem插入之前,因此如果发票插入失败,InvoiceItem将不会执行。但是我将捕获异常,重

我正在制作一个发票系统,支持多个子公司,每个子公司都有自己的发票号码集,因此我有一个主键为(Subsidiary,InvoiceNo)的表

我不能使用MySQL自动递增字段,因为它将不断递增所有子数据的相同计数

我不想为每个子公司制作单独的表格,因为需要时会添加新的子公司

我目前正在使用表中的“选择最大(ID),其中子公司=X”,并根据此添加发票

我使用的是nHibernate,发票插入在InvoiceItem插入之前,因此如果发票插入失败,InvoiceItem将不会执行。但是我将捕获异常,重新检索Max(ID)并重试

这种方法有什么问题?如果有的话,还有什么替代方案


问这个问题的原因是因为我读了关于这个问题的一个答案:

正如您所说,这种方法的问题是多个会话可能会尝试插入相同的发票ID。您会遇到唯一的约束冲突,必须重试,也可能会失败,等等

我通过在创建新发票期间锁定子系统来解决此类问题。但是,不要锁定表,(a)如果使用InnoDB,默认情况下,
lock table
命令会出现问题。(b) 没有理由不同时添加两个不同子公司的发票,因为它们具有不同的独立发票号

在你的情况下,我会做的是:

  • 打开事务并确保您的表是InnoDB
  • 使用
    SELECT..锁定子系统。。用于更新
    命令。这可以在NHibernate中完成
  • 使用max(..)函数查找max id并进行插入
  • 提交事务

这将序列化一个子公司的所有发票插入(即,一次只能有一个会话执行此类插入,任何第二次尝试都将等待第一次完成或回滚),但这正是您想要的。您不希望发票号码出现漏洞(例如,如果您插入发票id 3485,然后它失败,则有发票3484和3486,但没有发票3485)。

正如您所说,这种方法的问题是多个会话可能会尝试插入同一发票id。您遇到唯一的约束冲突,必须重试,也可能失败,等等

我通过在创建新发票期间锁定子系统来解决此类问题。但是,不要锁定表,(a)如果使用InnoDB,默认情况下,
lock table
命令会出现问题。(b) 没有理由不同时添加两个不同子公司的发票,因为它们具有不同的独立发票号

在你的情况下,我会做的是:

  • 打开事务并确保您的表是InnoDB
  • 使用
    SELECT..锁定子系统。。用于更新
    命令。这可以在NHibernate中完成
  • 使用max(..)函数查找max id并进行插入
  • 提交事务

这将序列化一个子公司的所有发票插入(即,一次只能有一个会话执行此类插入,任何第二次尝试都将等待第一次完成或回滚),但这正是您想要的。您不希望在发票号码中出现漏洞(例如,如果您插入发票id 3485,然后失败,则有发票3484和3486,但没有发票3485)。

在生成主键时使用此方法是非常糟糕的。我的建议如下:

  • 不要赋予主键商业意义(合成键)

  • 使用辅助机制生成发票编号

这会让你的生活轻松很多。然后,生成发票编号的机制可以是一个类似以下内容的表:

  • 附属公司
  • 下一个语音号码
这将把内部编号与数据库的工作方式分开

使用这种机制,您将能够再次使用自动递增字段,甚至更好地使用GUID

与阅读材料的一些链接:


http://nhforge.org/blogs/nhibernate/archive/2009/02/09/nh2-1-0-new-generators.aspx

在生成主键时使用此选项是一个非常糟糕的主意。我的建议如下:

  • 不要赋予主键商业意义(合成键)

  • 使用辅助机制生成发票编号

这会让你的生活轻松很多。然后,生成发票编号的机制可以是一个类似以下内容的表:

  • 附属公司
  • 下一个语音号码
这将把内部编号与数据库的工作方式分开

使用这种机制,您将能够再次使用自动递增字段,甚至更好地使用GUID

与阅读材料的一些链接:


http://nhforge.org/blogs/nhibernate/archive/2009/02/09/nh2-1-0-new-generators.aspx

这看起来正是我要找的东西,你能再清理一下锁定过程吗。我是否需要从发票中选择*进行更新,其中subsidiary=x,然后在同一会话上进行另一个查询以获取最大id?您需要一个表
subsiduary
,其中每个subsiduary有一行。这将是您要锁定的那一行,以显示子公司正在进行独占操作<代码>启动事务,然后
从子系统中选择id,其中子系统\u id=?对于UPDATE
,然后从invoice…,
INSERT…
COMMIT
中选择MAX(id)。这样,当您锁定附属表中的附属行时,就不允许插入任何将该行作为外键约束的新记录了吗?对吗?不完全正确;如果你锁上