下面是我的数据库结构的简化版本(在MVC 2中构建一个概念证明站点,其中Entity Framework 4作为我的ORM):
[Stores]
StoreID (PK)
StoreName
[Items]
ItemID (PK)
ItemName
Description
StoreID (FK)
[ItemSizes]
SizeID (PK)
SizeName
Price
ItemID (FK)
[Users]
UserID (PK)
UserName
商店出售各种尺寸的商品. [Users]代表标准的asp.net会员商店.
我想实现能够“喜欢”并对特定项目(和大小)进行评级的用户,所以我最初的冲动是实现几个基本的映射表:
[FavouriteSizes]
UserID (PK) (FK)
SizeID (PK) (FK)
[ItemRatings]
UserID (PK) (FK)
ItemID (PK) (FK)
Rating
但是,如果我强制执行参照完整性,当店主希望删除项目,项目大小甚至关闭他/她的整个商店时,我当然会遇到问题.
我发现的选项是:
>级联删除:主要的骗局是用户下次登录时,他的受欢迎的项目完全丢失
>软/逻辑删除:在这种情况下,我正在回避它们,因为当我过去使用它们时,必须为每个查询添加WHERE IsActive会使表联接变得麻烦.另外我相信(如果我错了,请纠正我)这会增加EF4的复杂性,例如Items.Includes(“ItemSizes”).
>不执行参照完整性(在[FavouriteSizes] .SizeID FK和[ItemRatings] .ItemID FK):我以前从未实际做过这个.这似乎是“最简单”的答案,但我不确定它是否会在以后回来咬我.
鉴于不执行这两个外键约束似乎是最简单的选项,我的实现将是:
>将ItemName添加到[FavouriteSizes],并在用户收藏大小时使用ItemSize.Item.ItemName填充它
>添加帮助以在优惠项目不再可用时显示通知(FavouritedSize.Items Is Nothing),以便用户可以从其收藏夹列表中删除该项目.
>确保任何“评级最高的项目”类型报告仅回收仍然存在的项目.
这种实施是否会引发问题?有足够的理由说明为什么我应该去实现软删除而不是仅仅执行引用完整性(除了保留报告的历史数据)?我错过了一个更适合的选择吗?
最佳答案 不强制执行参照完整性是一件很危险的事情,除非您完全确定没有任何一个应用程序将填充此表中的数据(并且您的应用程序当然经过测试以确保其保持完整性)
在实际情况中,我发现这种方法存在风险,因为一旦系统投入生产,总有可能会出现其他应用程序,尤其是数据迁移工具/补丁/某些紧急情况下的某些直接数据操作 – 最终操纵数据并且在没有约束的情况下,他们将无法识别关系,并可能最终输入不正确的数据.
另外,我不知道你是否需要这个输入,但看看你的架构,我可能会考虑稍微改变
[Stores]
StoreID (PK)
StoreName
[Items]
ItemID (PK)
ItemName
Description
StoreID (FK)
[Sizes]
SizeID (PK)
SizeName
[ItemSizes]
ItemID (PK)
SizeID (PK)
Price
[Users]
UserID (PK)
UserName
注意:我已将[ItemSizes]表拆分为[Sizes]和[ItemSizes].
通过这种方式,您可以收藏项目或尺寸(正如您当前所做的那样),甚至是特定尺寸的项目.
[FavouriteSizes]
UserID (PK) (FK)
SizeID (PK) (FK)
IsActive
[FavouriteItemSizes]
UserID (PK) (FK)
ItemID (PK) (FK)
SizeID (PK) (FK)
IsActive
[ItemRatings]
UserID (PK) (FK)
ItemID (PK) (FK)
Rating
IsActive
总而言之,添加IsActive字段,甚至是您的收藏夹和评级表 – 除了主表 – 使用WHERE IsActive检查和制作收藏夹/评级是软 – 删除项目/项目大小/尺寸后再删除显示您的收藏夹/评级的逻辑表明不存在先前添加的评级/收藏夹给用户,在我看来是更好的选择.
我不确定IsActive检查如何与EF一起使用 – 没有使用EF – 但总的来说,我会说确保检查始终存在于所有查询中,这很容易通过确保检查特定点来完成 – 作为审查过程.通常,它成为团队中的第二天性,并确保检查可以忽略不计.