我正在使用 SQL Server 2008 R2、C# 和 ASP.Net。我有一个表,它有一个由票号组成的复合主键,以及该票在表中出现的次数。票证频率由 C# 代码计算:

VTTTickets.InsertParameters[0].DefaultValue = VTTTTicketNoBox.Text;
string CommString = "SELECT COUNT(*) FROM [Tickets] WHERE [Ticket_No] = " +
VTTTTicketNoBox.Text;
string ConnString = ConfigurationManager.ConnectionStrings[1].ConnectionString;
OdbcConnection Conn = new OdbcConnection(ConnString);
Conn.Open();
OdbcCommand FooCommand = newOdbcCommand(CommString,Conn);
int FooVal = Convert.ToInt32(FooCommand.ExecuteScalar()) + 1;
VTTTickets.InsertParameters[1].DefaultValue = Convert.ToString(FooVal);
VTTTTicketNoBox.Text = "";
Conn.Close();

我的表约束/等代码
CONSTRAINT [PK_Tickets] PRIMARY KEY CLUSTERED
([Ticket_No] ASC, [Ticket_Sub_No] ASC)
WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = ON,
ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY],
CONSTRAINT [Unique_Ticket_No] UNIQUE NONCLUSTERED
([Ticket_No] ASC)
WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = ON,
ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY],
) ON [PRIMARY]
GO

唯一约束的原因是因为主组合键的那部分也是另外两个表的外键。
我不断收到的错误是它对我大喊大叫,因为在唯一约束列中存在重复的值。一旦一切从开发转移到生产,这可能会发生,因为可能会重新提交票证。

有没有办法在没有唯一键约束的情况下制作外键?
如果没有,我该如何解决这个问题?

最佳答案

这是我们在编程中经常遇到的情况之一。 Technology_A 不会让我做 Operation_B,但它应该!然后,在我们的头撞墙一段时间后,我们放弃了(或前往 Stackoverflow)。我们这样做是因为我们没有按照预期使用该技术(没关系,这就是我们学习的方式!)

这里的问题是您的数据库架构。

你试图用一张 table 做太多事情。您不应将票证(同一票证可能存在多次)存储在您正在跟踪发生次数的同一个表中。

在我看来,有两种很好的策略可以纠正这种情况。首先,我将创建一个带有单列主键的票证表。然后,我将创建一个表来存储票证的每个实例。

示例:Ticket43 已关闭,但重新打开并再次关闭。这意味着(如果我读对了您的问题),该票有两个实例。这意味着它在您的原始表中有两个条目,但在我新提议的模式中,它在 Tickets 中有一个条目,在 Ticket_Instances 中有两个条目。

注意:您需要确保在 Tickets 中存储在实例之间永远不会更改的票证信息,而在 Ticket_Instances 中存储特定于实例的票证信息。

要记录工单计数 ,我要做的第一件事就是简单地编写一个 View 或一些 SQL,如下所示:

SELECT
  count(*) as TicketCount,
  TicketID
FROM
  Ticket_Instances as TI
GROUP BY
  TicketID

如果您不想按需计算 ,那么我建议使用:
  • ASP.NET 缓存(运行上面的 SQL,将其塞入缓存,TTL 为 10 分钟)
  • 使用由触发器填充的 Ticket_Counts 表

  • 我怀疑你会更喜欢那里的选项 2(尽管我会使用选项 1)。

    触发方式:

    假设 Ticket_Instances 可能永远不会被删除,您只需要一个插入触发器。您将在插入时在 Ticket_Instances 表上创建一个触发器,该触发器 SQL 将执行以下操作:
  • 如果Ticket_Counts中不存在TicketID,则将TicketID插入Ticket_Counts中,TicketCount为0
  • 然后,将Ticket_Counts中TicketID的TicketCount加1

  • 使用此方法,您只需通过 TicketID 访问 Ticket_Counts 即可获取该特定故障单的出现次数。

    我认为您会发现一旦更新架构,您的约束错误就会消失。

    关于c# - 复合主键/外键头痛,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/5916890/

    10-11 12:18