外键是否可以引用标识字段?

时间:2015-12-04 15:38:10

标签: asp.net sql-server

假设我在ASP.NET MVC代码第一种方法中有以下模型:

public class City
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class Restaurant
{
    public int Id { get; set; }
    public int CityId { get; set; }
    public virtual City City { get; set; }
} 

这意味着我有一个名为City的表,其中包含:

  • Id(主键及其身份字段)
  • 名称(varchar)

另一个名为Restaurant的表格包含:

  • Id(主键及其身份字段)
  • CityId(City表中的外键重新标识ID,删除时没有级联)

现在因为我的城市数据是固定的而且变化不大,我使用种子方法来填充它:

context.Cities.AddOrUpdate(x => x.Name,
               new City() { Name = "Springfield" },
               new City() { Name = "Franklin" },
               new City() { Name = "Greenville" }
            );

请注意我没有分配任何ID,因为City Id是一个身份字段并且自动递增。

一个场景:

我担心的一个场景是这样的: 假设Restaurant表中有一些餐馆引用这些城市。现在随着时间的推移,由于某些未知原因,Franklin的Id为2会从City表中删除。因此,当您注意到发生了什么时,再次将Franklin作为城市插入,但这次它的ID已经更改。那么那些已经将“富兰克林”称为他们的城市的餐馆会发生什么呢?

我应该使City Id不是一个身份主键,而只是一个整数主键并自己分配City ID吗?

如果我在外键上启用级联删除,那么我将丢失引用已删除城市的记录,我不希望这样。我想保留它们,直到我弄清楚删除的城市发生了什么并解决问题。

问题

所以有了这些信息,就我而言,从身份字段制作外键是一个好习惯吗?处理这种情况的最佳方法是什么?

2 个答案:

答案 0 :(得分:4)

主键和外键确保称为“参照完整性”。就像听起来一样,它们确保了数据中包含的引用的完整性。如果你在一个城市有餐馆,你不应该被允许删除那个城市,因为它会破坏引用的完整性(即你现在有孤儿餐馆)。另一种方法是,如果删除城市,则允许数据库删除餐馆。这些场景中的任何一种(阻止删除或级联删除)都可以使用外键完成。

每当一个表中的数据依赖于另一个表中的数据时,您应该创建一个外键,以确保不会导致数据损坏。它是一个标识列的事实是无关紧要的。

您的数据库是防御损坏数据的最后一道防线。您希望确保不允许导致删除行的“未知原因”。首先防止问题比在数据损坏后尝试修复数据更容易。

答案 1 :(得分:1)

只要有餐厅引用它,您就无法从表格中删除任何城市。

这将由外键强制执行。 (您可以在创建外键时自定义此项:ON DELETE CASCADE,ON DELETE SET NULL ...)

所以答案是肯定的:这是一个很好的做法。