Мягкие/логические удаления против отсутствия ссылочной целостности против?

Ниже приведена упрощенная версия моей структуры базы данных (создание экспериментального сайта в 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): я никогда не делал этого раньше. Это кажется «самым простым» ответом, но я не уверен, что он вернется ко мне позже.

Учитывая, что неприменение этих двух ограничений внешнего ключа кажется самым простым вариантом, моя реализация будет такой:

  1. Добавьте ItemName к [FavouriteSizes] и заполните его ItemSize.Item.ItemName, когда пользователь добавляет размер в избранное.
  2. Добавьте помощника для отображения уведомления, если избранный элемент больше недоступен (FavouritedSize.Items Is Nothing), чтобы пользователи могли удалить этот элемент из своего списка избранного.
  3. Убедитесь, что любой отчет типа «Элементы с самым высоким рейтингом» извлекает только те элементы, которые все еще существуют.

Эта реализация вызовет проблемы в будущем? Есть ли достаточно веская причина, по которой я должен утруждать себя реализацией обратимого удаления вместо того, чтобы просто не обеспечивать ссылочную целостность (кроме сохранения исторических данных для отчетов)? Я пропустил вариант, который подошёл бы лучше?


person Matt O'D    schedule 08.12.2010    source источник


Ответы (1)


Несоблюдение ссылочной целостности — рискованная вещь, если вы абсолютно и полностью не уверены, что НИКТО, КРОМЕ ВАШЕГО приложения, никогда не будет заполнять данные в этой таблице (и что ваше приложение, конечно же, протестировано, чтобы гарантировать, что оно сохраняет целостность)

В практическом сценарии я нашел этот подход рискованным, потому что, как только система запущена в производство, всегда есть вероятность того, что появятся другие приложения, особенно инструменты миграции данных/исправления/некоторые прямые манипуляции с данными в некоторых срочных сценариях. - которые в конечном итоге манипулируют данными, и при отсутствии ограничения у них не будет возможности идентифицировать взаимосвязь, и потенциально они могут в конечном итоге ввести неверные данные.

Кроме того, я не знаю, нужен ли вам этот ввод, но, глядя на вашу схему, я бы, вероятно, подумал о небольшом изменении.

[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, но в целом я бы сказал, что убедиться, что проверка всегда присутствует во всех запросах, легко, гарантируя, что конкретная точка проверена - как часть процесс обзора. Обычно это становится второй натурой в команде, и дополнительные усилия по обеспечению такой проверки незначительны.

person Jagmag    schedule 08.12.2010
comment
Спасибо за дополнительный ввод схемы ... Я не добавлял таблицу дополнительных размеров, потому что информация о размерах зависит от магазина: в некоторых магазинах используются маленькие - 5 долларов, большие - 15 долларов, другие используют 5 для 10 долларов, 10 для 15 долларов, в зависимости от того, какой магазин продается и что это за товар. - person Matt O'D; 08.12.2010