Что такое лучшая практика для этой проблемы (различные свойства для различных категорий)?

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

 public interface IRepository
 {
     List<Student> GetAllStudents();
     void AddStudent(Student student);
     Teacher GetStudentTeacher(int studentId);
 }

 public class MockRepository : IRepository
 {
     public static List<Student> Students { get; set; }
     public static List<Teachers> Teachers { get; set; }

     static MockRepository()
     {
         Students = new List<Student>();
     }

     public List<Student> GetAllStudents()
     {
         return Students.ToList();
     }

     public void AddStudent(Student student)
     {
         Students.Add(student);
     }

     public Teacher GetStudentTeacher(int studentId)
     {
         var student = Students.FirstOrDefault(s => s.Id == studentId);
         if (student != null)
         {
             return Teachers.FirstOrDefault(t => t.Id == student.TeacherId);
         }

         return null;
     }
 }

Верхний уровень может быть ответственным за создание исключения в случае, если у ученика уже есть учитель, и есть попытка добавить второй.

6
задан Bill Karwin 14 February 2009 в 20:48
поделиться

8 ответов

Классический подход дизайна был бы (звезда обозначает столбец первичного ключа):

Product
  ProductId*
  CategoryId: FK to Category.CategroyId
  Name

Category
  CategoryId*
  Name

Property
  PropertyId*
  Name
  Type

CategoryProperty
  CategoryId*: FK to Category.CategoryId
  PropertyId*: FK to Property.PropertyId

ProductProperty
  ProductId*: FK to Product.ProductId
  PropertyId*: FK to Property.PropertyId
  ValueAsString

Если бы можно жить с тем, что каждое значение свойства перешло бы к DB, поскольку информация о преобразовании строк и преобразовании типов хранится в таблице Property, это расположение было бы достаточно.

Запрос прошел бы примерно так:

SELECT
   Product.ProductId,
   Product.Name AS ProductName,
   Category.CategoryId,
   Category.Name AS CategoryName,
   Property.PropertyId,
   Property.Name AS PropertyName,
   Property.Type AS PropertyType,
   ProductProperty.ValueAsString
FROM
   Product 
   INNER JOIN Category         ON Category.CategoryId = Product.CategoryId
   INENR JOIN CategoryProperty ON CategoryProperty.CategoryId = Category.CategoryId
   INNER JOIN Property         ON Property.PropertyId = CategoryProperty.PropertyId
   INNER JOIN ProductProperty  ON ProductProperty.PropertyId = Property.PropertyId
                                  AND ProductProperty.ProductId = Product.ProductId
WHERE
   Product.ProductId = 1

Чем больше, ГДЕ условия Вы предоставляете (conjunctively, например, использование И), тем быстрее запрос будет. Если Вы правильно индексировали свои таблицы, который является.

Как это, решение не идеально для ситуации с полнотекстовым индексированием. Дополнительная таблица, которая хранит весь текст, связанный с ProductId более денормализованным способом, могла помочь здесь. Этой таблице было бы нужно обновление через триггеры, которые прислушиваются к изменениям в таблице ProductProperty.

13
ответ дан 8 December 2019 в 04:32
поделиться

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

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

Обратите внимание на то, что, если у Вас будут продукты, которые Вы хотите перечисленный в нескольких категориях, то это решение приведет к дублирующимся данным в Ваших таблицах. Существует компромисс между скоростью и нормализацией при разработке базы данных. Если у Вас нет продуктов, которые помещаются в несколько категорий, то я думаю, что это будет быстрым решением (с точки зрения поисковой скорости).

8
ответ дан 8 December 2019 в 04:32
поделиться

Большинство людей советует для использования изменений дизайна Значения атрибута объекта (EAV). Этот дизайн является излишеством для Вашей ситуации, и это представляет целый набор проблем, например:

  • Вы не можете определить тип данных для атрибута; можно ввести "банан" для целочисленного атрибута
  • Вы не можете объявить атрибут как обязательный (т.е. NOT NULL в стандартной таблице)
  • Вы не можете объявить ограничение внешнего ключа на атрибут

Если у Вас есть небольшое количество категорий, лучше использовать решение A в ответе Bogdan Maxim. Таким образом, определите продукты таблицы с атрибутами, характерными для всех категорий и одной дополнительной таблицы для каждой категории, для хранения определенных для категории атрибутов.

Только если у Вас есть бесконечное число категорий или если необходимо потенциально поддерживать другой набор атрибутов на строку в продуктах, EAV хорошее решение. Но затем Вы не используете реляционную базу данных вообще, так как EAV нарушает несколько правил нормализации.

При реальной необходимости в так большой гибкости Вы были бы более обеспеченным хранением Ваших данных в XML. На самом деле Вы могли бы изучить RDF и платформы семантической паутины как Сезам.

2
ответ дан 8 December 2019 в 04:32
поделиться

Вы могли бы хотеть рассмотреть тип Значения атрибута объекта расположения, где можно "отметить" каждый продукт с произвольными парами имя/значение атрибутов.

1
ответ дан 8 December 2019 в 04:32
поделиться

Если Вы хотите быть гибкими на своих категориях и свойствах, необходимо создать следующие таблицы:

  • продукт: ProductID
  • категория: CategoryID, ProductID
  • свойство: PropertyID, CategoryID

когда Вы хотите совместно использовать категорию по mroe, чем один продукт, необходимо составить таблицу ссылки для соединения n:m:

  • productCategoryPointer: ProdCatID, ProductID, CategoryID.

Вы будете иметь к некоторым, участвует в Ваших запросах, но с правильными индексами, Вы shoulb смочь запросить Ваши данные быстро.

0
ответ дан 8 December 2019 в 04:32
поделиться

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

5 таблиц. 3 для того, чтобы хранить данные, 2 для хранения отображений между данными.

tProduct 
  productID
  <other product details>

tCategory
  categoryID
  <other category details>

tProperty
  propertyID
  <other property details>

tProductXCategory
  productyID
  categoryID

tCategoryXProperty
  categoryID
  propertyID

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

Используйте хранимые процедуры или параметризированные запросы для вытаскивания лучшей производительности из поисков.

1
ответ дан 8 December 2019 в 04:32
поделиться

Вы могли попробовать что-то более объектно-ориентированное.

1. Определите базовую таблицу для продуктов

Products(ProductID, CategoryID, <any other common properties>)

2. Определите категории таблиц

Categories(CategoryID, Name, Description, ..)

Отсюда у Вас есть много опций, и почти все они повредят нормализацию Вашей базы данных.

Решение A.

Будет maintaince кошмар, если необходимо добавить новые продукты

A1. Определите отдельную таблицу для каждой из категорий

Cars(CarID, ProductID, ..) Pets(PetID, ProductID, ..)

A2. Присоединитесь к таблицам на основе отношений для использования данных

SELECT <fields> FROM Cars INNER JOIN Products ON Cars.ProductID = Products.ProductID

Решение B.

Кошмар Maintainance для различных типов свойств (т.е. интервал, varchar, и т.д.)

B1. Определите таблицу для Свойств

CategoryProperty (CPID, Name, Type)

B2. Определите таблицу для содержания ассоциаций между Категориями и Свойствами

PropertyAssociation (CPID, PropertyID)

B12. Определите таблицу для содержания свойств (Альтернатива для B1 и B2)

Properties(CategoryID, PropertyID, Name, Type)

B3. Для каждого типа свойства (интервал, дважды, varchar, и т.д.) добавляют таблицу значений

PropertyValueInt(ProductID, CPID, PropertyID, Value) - для интервала PropertyValueString(ProductID, CPID, PropertyID, Value) - для строк PropertyValueMoney(ProductID, CPID, PropertyID, Value) - за деньги

B4. Присоединитесь ко всем таблицам для получения желаемого свойства.

При помощи этого подхода Вы не должны будете управлять всеми свойствами в отдельной таблице, но типами значения их. В основном все включенные таблицы будут справочными таблицами. Недостаток, то, что для получения каждого значения необходимо "Случиться" для каждого типа значения.

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

Вы могли также использовать ответ Tomalak и добавить строгий контроль типов, если Вы чувствуете потребность.

0
ответ дан 8 December 2019 в 04:32
поделиться

Я недавно должен был сделать это, и я использую NHibernate, где у меня есть три объекта

Опция категории продуктов OptionCategory

Продукт имеет 1* Категории

Продукт имеет 1* Опция

Опция имеет 1 OptionCategory

после того как это настраивается, можно использовать кэширование Nhibernate

Удачи

0
ответ дан 8 December 2019 в 04:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: