c# - 复合主键/外键头痛

标签 c# asp.net sql-server-2008 foreign-keys composite-primary-key

我正在使用 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 做太多事情。您不应将票证(同一张票证可能存在不止一次)存储在您正在跟踪 # of occurrences 的同一个表中。

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

enter image description here

示例: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,以 10 分钟的 TTL 将其塞入缓存)
  • 使用由触发器填充的 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/

相关文章:

c# - 如何将一个 XML 文件拆分为多个 XML 文件

mysql - 来自不同表的复杂浮点计算

c# - 在 Screen Scraping 中工作时出现页面发布问题

sql - 如何从临时表选择中删除第一列

sql - 比较两列的组合与 SQL 中其他两列的组合

c# - Microsoft Xna Texture2D 和旋转

c# - 以下查询中 sql 注入(inject)的可能性

c# - Entity Framework .include 性能问题

asp.net - 在 asp.net 中全局设置每个控件的 ValidationGroup 属性的最佳方法?

css - 如何更改 asp 下拉列表所有元素的字体系列?