软/逻辑删除 vs 无引用完整性 vs ...?
下面是我的数据库结构的简化版本(使用 Entity Framework 4 作为我的 ORM 在 MVC 2 中构建概念验证站点):
[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
),以便用户可以从其收藏中删除该商品收藏夹列表。 - 确保任何“最受好评的项目”类型报告仅撤回仍然存在的项目。
此实施会在以后引起问题吗?是否有足够充分的理由说明为什么我应该不厌其烦地实施软删除,而不是仅仅不强制执行引用完整性(除了保留用于报告的历史数据之外)?我是否缺少一个更适合的选项?
Below is a simplified version of my database structure (building a proof of concept site in MVC 2 with Entity Framework 4 as my ORM):
[Stores]
StoreID (PK)
StoreName
[Items]
ItemID (PK)
ItemName
Description
StoreID (FK)
[ItemSizes]
SizeID (PK)
SizeName
Price
ItemID (FK)
[Users]
UserID (PK)
UserName
Stores sell items, which come in varying sizes. [Users]
represents the standard asp.net membership store.
I'd like to implement users being able to "favourite" and rate particular Items (and Sizes) so my initial impulse was to implement a couple of basic mapping tables:
[FavouriteSizes]
UserID (PK) (FK)
SizeID (PK) (FK)
[ItemRatings]
UserID (PK) (FK)
ItemID (PK) (FK)
Rating
However, if I enforce referential integrity, I will of course run into an issue when a store owner wants to delete an item, item size, or even shut down his/her whole store.
The options I've identified are:
- Cascading Deletes: The major con being the next time a user logs in, his favourited items are missing entirely
- Soft/Logical Deletes: I'm shying away from them in this case because when I've used them in the past, having to add
WHERE IsActive
to every query gets cumbersome with table joins. Plus I believe (correct me if I'm wrong) this adds some complexity in EF4 with, say,Items.Includes("ItemSizes")
. - Not Enforcing Referential Integrity (on the
[FavouriteSizes].SizeID
FK and[ItemRatings].ItemID
FK only): I've never actually done this before. It seems like the "easiest" answer, but I'm not sure if it will come back to bite me later.
Given that not enforcing those 2 foreign key constraints seems like the simplest option, my implementation would be:
- Add
ItemName
to[FavouriteSizes]
, and populate it withItemSize.Item.ItemName
when a user favourites a size - Add a helper to display a notification if a favourited item is no longer available (
FavouritedSize.Items Is Nothing
) so users can remove that item from their favourites list. - Ensure that any "Top Rated Items" type reporting only pulls back items that still exist.
Is this implementation going to cause problems down the road? Is there a strong enough reason why I should go to the trouble of implementing soft deletes instead of just not enforcing referential integrity (other than preserving historical data for reporting)? Am I missing an option that would fit better?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
不强制执行引用完整性是一件有风险的事情,除非您绝对完全确定除了您的应用程序之外没有人会填充此表中的数据(并且您的应用程序当然经过测试以确保其保持完整性
)在实际场景中,我发现这种方法存在风险,因为一旦系统投入生产,总是有可能出现其他应用程序,特别是在某些紧急情况下的数据迁移工具/补丁/一些直接数据操作 -最终会操纵数据,并且在没有约束的情况下,他们将无法识别关系,并且可能最终会输入不正确的数据。
此外,我不知道您是否需要此输入,但查看您的架构,我可能会考虑稍作更改
注意:我已将您的
[ItemSizes]
表拆分为[Sizes]和<代码>[ItemSizes]。
这样,您可以收藏某个商品或某个尺寸(正如您当前所做的那样),甚至可以收藏特定尺寸的商品。
总而言之,添加
IsActive
字段,甚至添加到您的收藏夹和评级表 - 除了您的主表之外 - 使用WHERE IsActive
检查并使收藏夹/评级软 - 删除删除项目/项目大小/大小,然后显示您的收藏夹/评级的附加逻辑,以指示用户不存在先前添加的评级/收藏夹,在我看来是更好的选择。我不太确定 IsActive 检查如何与 EF 一起使用 - 没有使用过 EF - 但总的来说,我想说,通过确保检查特定点可以轻松地确保检查始终存在于所有查询中 - 作为审查过程。通常,它成为团队内的第二天性,并且确保检查可以忽略不计的额外努力。
Not enforcing the Referential Integrity is a risky thing to do unless you are absolutely and completely sure that NO ONE BUT YOUR application is going to ever populate data in this table (and that your application is of course tested to ensure it preserves the integrity)
In a practical scenario, i have found this approach to be risky because once a system is live in production, there is always a possibility that there will be other applications coming up especially data migration tools / patches / some direct data manipulation in some urgent scenarios - which end up manipulating the data and in the absence of a constraint, they will have no way to identify the relationship and could potentially end up putting in data that is incorrect.
Additionally, i dont know if you need this input, but looking at your schema, i would probably consider a slight change
Note: I have split your
[ItemSizes]
table into[Sizes]
and[ItemSizes]
.This way, you can favourite, either an Item or a Size (as you are currently doing) or even an item of a specific size.
To summarize, Adding
IsActive
fields, even to your Favourite and Rating tables - in addition to your master tables - usingWHERE IsActive
check and making favourites / ratings are soft - deleted on removal of the item / item size / size and then having the additional logic on display of your favourites / ratings to indicate the non - existence of earlier added ratings / favourites to the user, seems to me the better option.I am not specifically sure of how the IsActive check works with EF - havent used EF - but in general, i would say that making sure that check is always present in all queries is done easily by ensuring that specific point is checked - as part of the review process. Usually, it becomes 2nd nature within a team and the additional effort to ensure that check is negligible.