基于复合主键的自动增量标识 [英] Auto-increment Id based on composite primary key

查看:110
本文介绍了基于复合主键的自动增量标识的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意:使用Sql Azure&实体框架6



说我有一个商店发票的下表(DB中有多个商店)...

$ b (
[InvoiceId] INTEGER NOT NULL,
[StoreId] UNIQUEIDENTIFIER NOT NULL,
$

CONSTRAINT [PK_Invoice] PRIMARY KEY CLUSTERED([InvoiceId] ASC,[StoreId] ASC)
);

理想情况下,我希望InvoiceId连续递增每个StoreId,而不是独立于每个商店。 。

  InvoiceId | StoreId 
-------------------
1 | 'A'
2 | 'A'
3 | 'A'
1 | 'B'
2 | 'B'

问题: code> [InvoiceId] 根据 [StoreId]



可能的选项:



a)理想的一个 [InvoiceId] INTEGER NOT NULL IDENTITY_BASED_ON([StoreId])参数某种方式会真的很有帮助,但我怀疑这是否存在...



b)一种基于另一列从函数返回设置默认值的方法? (AFAIK,您不能在默认情况下引用另一列)

  CREATE FUNCTION [dbo]。[NextInvoiceId] 

@storeId UNIQUEIDENTIFIER

RETURNS INT
AS
BEGIN
DECLARE @nextId INT;
SELECT @nextId = MAX([InvoiceId])+ 1 FROM [Invoice] WHERE [StoreId] = @storeId;
IF(@nextId IS NULL)
返回1;

RETURN @nextId;


CREATE TABLE [dbo]。[发票](
[InvoiceId] INTEGER NOT NULL DEFAULT NextInvoiceId([StoreId]),
[StoreId] UNIQUEIDENTIFIER NOT NULL,

CONSTRAINT [PK_Invoice] PRIMARY KEY CLUSTERED([InvoiceId] ASC,[StoreId] ASC)
);

c)一种在Entity Framework中处理此问题的方法(使用 DbContext.SaveChangesAsync 覆盖或设置自定义插入查询?



注意:我意识到我可以做到一个存储过程插入发票,但我宁愿避免,除非它的唯一选项。

解决方案

您应该坚持使用自动递增的整数主键,这比处理复合主键要简单得多,特别是当将事情与发票相关联时。



为了为用户生成一个InvoiceNumber,每个商店的增量可以使用 ROW_NUMBER 功能 StoreId 并由您的自动递增主键排序。



下面的示例演示了以下示例:

  WITH TestData InvoiceId,StoreId)AS 

SELECT 1,'A'
UNION SELECT 2,'A'
UNION SELECT 3,'A'
UNION SELECT 4, 'B'
UNION SELECT 5,'B'

选择InvoiceId,
StoreId,
ROW_NUMBER()OVER(PARTITION BY StoreId ORDER BY InvoiceId)AS InvoiceNumber
FROM TestData

结果:

 
InvoiceId | StoreId | InvoiceNumber
1 | A | 1
2 | A | 2
3 | A | 3
4 | B | 1
5 | B | 2


Note: Using Sql Azure & Entity Framework 6

Say I have the following table of a store's invoices (there are multiple stores in the DB)...

CREATE TABLE [dbo].[Invoice] (
    [InvoiceId] INTEGER NOT NULL,
    [StoreId] UNIQUEIDENTIFIER NOT NULL,

    CONSTRAINT [PK_Invoice] PRIMARY KEY CLUSTERED ([InvoiceId] ASC, [StoreId] ASC)
);

Ideally, I would like the InvoiceId to increment consecutively for each StoreId rather than independent of each store...

InvoiceId | StoreId
-------------------
1         | 'A'
2         | 'A'
3         | 'A'
1         | 'B'
2         | 'B'

Question: What is the best way to get the [InvoiceId] to increment based on the [StoreId]?

Possible options:

a) Ideally a [InvoiceId] INTEGER NOT NULL IDENTITY_BASED_ON([StoreId]) parameter of some kind would be really helpful, but I doubt this exists...

b) A way to set the default from the return of a function based on another column? (AFAIK, you can't reference another column in a default)

CREATE FUNCTION [dbo].[NextInvoiceId]
(
    @storeId UNIQUEIDENTIFIER
)
RETURNS INT
AS
BEGIN
    DECLARE @nextId INT;
    SELECT @nextId = MAX([InvoiceId])+1 FROM [Invoice] WHERE [StoreId] = @storeId;
    IF (@nextId IS NULL)
        RETURN 1;

    RETURN @nextId;
END

CREATE TABLE [dbo].[Invoice] (
    [InvoiceId] INTEGER NOT NULL DEFAULT NextInvoiceId([StoreId]),
    [StoreId] UNIQUEIDENTIFIER NOT NULL,

    CONSTRAINT [PK_Invoice] PRIMARY KEY CLUSTERED ([InvoiceId] ASC, [StoreId] ASC)
);

c) A way to handle this in Entity Framework (code first w/o migration) using DbContext.SaveChangesAsync override or by setting a custom insert query?

Note: I realize I could do it with a stored procedure to insert the invoice, but I'd prefer avoid that unless its the only option.

解决方案

You should stick to an auto-incrementing integer primary key, this is much simpler than dealing with a composite primary key especially when relating things back to an Invoice.

In order to generate an InvoiceNumber for the sake of a user, which increments per-store, you can use a ROW_NUMBER function partitioned by StoreId and ordered by your auto-incrementing primary key.

This is demonstrated with the example below:

WITH TestData(InvoiceId, StoreId) AS
(
    SELECT 1,'A'
    UNION SELECT 2,'A'
    UNION SELECT 3,'A'
    UNION SELECT 4,'B'
    UNION SELECT 5,'B'
)
Select InvoiceId,
        StoreId,
        ROW_NUMBER() OVER(PARTITION BY StoreId ORDER BY InvoiceId) AS InvoiceNumber
FROM TestData

Result:

InvoiceId | StoreId | InvoiceNumber
1         | A       | 1  
2         | A       | 2  
3         | A       | 3  
4         | B       | 1  
5         | B       | 2  

这篇关于基于复合主键的自动增量标识的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆