Лучшие практики с кодом или таблицами поиска
[ОБНОВЛЕНИЕ] Выбранный подход ниже, как ответ на этот вопрос
Привет,
Я искал в этой теме, но я не могу найти то, что я ищу...
Под таблицами кодов я имею в виду: такие вещи, как "семейное положение", пол, конкретные правовые или социальные состояния... Более конкретно, эти типы имеют только установленные свойства, и элементы не собираются изменяться в ближайшее время (но могут). Свойства, являющиеся Id, именем и описанием.
Мне интересно, как справиться с этим лучше всего в следующих технологиях:
в базе данных (несколько таблиц, одна таблица с разными кодовыми ключами...?)
создание классов (вероятно, что-то вроде наследования ICode с ICode.Name и ICode.Description)
создание представления / докладчика для этого: должен быть экран, содержащий все из них, поэтому список типов (пол, семейное положение...), а затем список значений для этого типа с именем и описанием для каждого элемент в списке значений.
Это вещи, которые появляются в каждом отдельном проекте, поэтому должна быть лучшая практика, как справиться с этими...
Кстати, я не очень люблю использовать перечисления для этих ситуаций... Любые аргументы об их использовании здесь тоже приветствуются.
[СЛЕДОВАТЬ ЗА]
Хорошо, я получил хороший ответ от CodeToGlory и Ahsteele. Давайте уточним этот вопрос.
Скажем, мы говорим не о поле или семейном положении, значения которого определенно не изменятся, а о "вещах", которые имеют имя и описание, но не более того. Например: Социальные статусы, Правовые статусы.
UI: Я хочу только один экран для этого. Окно списка с возможными типами NameAndDescription (я назову их так), поле со списком возможных значений для выбранного типа NameAndDescription, а затем поле Имя и описание для выбранного элемента типа NameAndDescription.
Как это можно сделать в View & Presenters? Я нахожу здесь трудность в том, что типы NameAndDescription должны быть извлечены из имени класса?
ДБ: Каковы плюсы / минусы для нескольких таблиц поиска и сравнения?
6 ответов
Я решил пойти с этим подходом:
CodeKeyManager mgr = new CodeKeyManager();
CodeKey maritalStatuses = mgr.ReadByCodeName(Code.MaritalStatus);
Куда:
- CodeKeyManager может извлекать CodeKeys из БД (CodeKey=MaritalStatus)
- Код - это класс, заполненный константами, возвращающими строки, поэтому Code.MaritalStatus = "maritalStatus". Эти константы соответствуют таблице CodeKey> CodeKeyName
- В базе данных у меня есть 2 таблицы:
- CodeKey с идентификатором, CodeKeyName
- CodeValue с CodeKeyId, ValueName, ValueDescription
DB:
http://lh3.ggpht.com/_cNmigBr3EkA/SeZnmHcgHZI/AAAAAAAAAFU/2OTzmtMNqFw/codetables_1.JPG
Код класса:
public class Code
{
public const string Gender = "gender";
public const string MaritalStatus = "maritalStatus";
}
Класс CodeKey:
public class CodeKey
{
public Guid Id { get; set; }
public string CodeName { get; set; }
public IList<CodeValue> CodeValues { get; set; }
}
Класс CodeValue:
public class CodeValue
{
public Guid Id { get; set; }
public CodeKey Code { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
Я считаю самый простой и эффективный способ:
- Все кодовые данные могут отображаться одинаковым образом (в одном представлении / представителе)
- Мне не нужно создавать таблицы и классы для каждой таблицы кода, которая будет
- Но я все еще могу легко извлечь их из базы данных и легко использовать с константами CodeKey...
- NHibernate может справиться с этим тоже легко
Единственное, что я все еще рассматриваю, - это выбросить идентификаторы GUID и использовать строковые (nchar) коды для удобства использования в бизнес-логике.
Спасибо за ответы! Если есть какие-либо замечания по этому подходу, пожалуйста, сделайте!
Использование таблиц кода на основе базы данных может быть очень полезным. Вы можете сделать такие вещи, как определить срок действия данных (используя даты начала и окончания), добавить данные в таблицу в режиме реального времени, чтобы вам не пришлось развертывать код, и вы можете разрешить пользователям (с правильными привилегиями, конечно) добавить данные через экраны администратора.
Я бы рекомендовал всегда использовать первичный ключ autonumber, а не код или описание. Это позволяет вам использовать несколько кодов (с одинаковыми именами, но разными описаниями) в разные периоды времени. Кроме того, большинство администраторов баз данных (по моему опыту) предпочитают использовать автонумерацию поверх текстовых первичных ключей.
Я бы использовал одну таблицу для каждого закодированного списка. Вы можете поместить несколько кодов в одну таблицу, которые не связаны между собой (используя какую-то матрицу), но это становится беспорядочным, и я нашел только пару ситуаций, где это было даже полезно.
Пара вещей здесь:
Используйте перечисления, которые явно понятны и не изменятся. Например, MaritalStatus, Gender и т. Д.
Используйте таблицы поиска для элементов, которые не зафиксированы, как указано выше, и могут изменяться, увеличиваться / уменьшаться со временем.
Очень типично иметь таблицы поиска в базе данных. Определите ключ / значение объекта на вашем бизнес-уровне, который может работать с вашим представлением / представлением.
Почему все хотят усложнять кодовые таблицы? Да, их много, но они просты, так что держите их так. Просто относитесь к ним как к любому другому предмету. Они являются частью домена, поэтому моделируйте их как часть домена, ничего особенного. Если вам это не нужно, когда им неизбежно понадобятся дополнительные атрибуты или функциональные возможности, вам придется отменить весь код, который в данный момент использует его, и переработать его.
Разумеется, по одной таблице (для ссылочной целостности и чтобы они были доступны для отчетов).
Для классов, опять же, по одному на каждый, потому что, если я напишу метод для получения объекта "Gender", я не хочу иметь возможность случайно передать ему "MarritalStatus"! Пусть компиляция поможет вам отсеять ошибку времени выполнения, поэтому она есть. Каждый класс может просто наследовать или содержать класс CodeTable или любой другой, но это просто помощник реализации.
Для пользовательского интерфейса, если он действительно использует унаследованный CodeTable, я полагаю, вы могли бы использовать это, чтобы помочь вам и просто поддерживать его в одном пользовательском интерфейсе.
Как правило, не портите модель базы данных, не портите бизнес-модель, но если вы немного разберетесь в модели пользовательского интерфейса, это не так уж и плохо.
Я хотел бы рассмотреть возможность упрощения этого подхода еще больше. Вместо 3 таблиц, определяющих коды (Code, CodeKey и CodeValue), как насчет одной таблицы, которая содержит как типы кодов, так и значения кодов? Ведь типы кодов - это просто еще один список кодов.
Возможно определение таблицы как это:
CREATE TABLE [dbo].[Code](
[CodeType] [int] NOT NULL,
[Code] [int] NOT NULL,
[CodeDescription] [nvarchar](40) NOT NULL,
[CodeAbreviation] [nvarchar](10) NULL,
[DateEffective] [datetime] NULL,
[DateExpired] [datetime] NULL,
CONSTRAINT [PK_Code] PRIMARY KEY CLUSTERED
(
[CodeType] ASC,
[Code] ASC
)
GO
Может быть корневая запись с CodeType=0, Code=0, которая представляет тип для CodeType. Все записи CodeType будут иметь CodeType = 0 и Code>=1. Вот некоторые примеры данных, которые могут помочь прояснить ситуацию:
SELECT CodeType, Code, Description FROM Code
Results:
CodeType Code Description
-------- ---- -----------
0 0 Type
0 1 Gender
0 2 Hair Color
1 1 Male
1 2 Female
2 1 Blonde
2 2 Brunette
2 3 Redhead
В таблицу Code можно добавить проверочное ограничение, чтобы убедиться, что в таблицу введен правильный CodeType:
ALTER TABLE [dbo].[Code] WITH CHECK ADD CONSTRAINT [CK_Code_CodeType]
CHECK (([dbo].[IsValidCodeType]([CodeType])=(1)))
GO
Функция IsValidCodeType может быть определена так:
CREATE FUNCTION [dbo].[IsValidCodeType]
(
@Code INT
)
RETURNS BIT
AS
BEGIN
DECLARE @Result BIT
IF EXISTS(SELECT * FROM dbo.Code WHERE CodeType = 0 AND Code = @Code)
SET @Result = 1
ELSE
SET @Result = 0
RETURN @Result
END
GO
Одна из поднятых проблем заключается в том, как обеспечить, чтобы таблица со столбцом кода имела правильное значение для этого типа кода. Это также может быть обеспечено проверочным ограничением с использованием функции.
Вот таблица Person, в которой есть столбец с полами. Рекомендуется назвать все столбцы кода с описанием типа кода (в данном примере это Gender), за которым следует слово Code:
CREATE TABLE [dbo].[Person](
[PersonID] [int] IDENTITY(1,1) NOT NULL,
[LastName] [nvarchar](40) NULL,
[FirstName] [nvarchar](40) NULL,
[GenderCode] [int] NULL,
CONSTRAINT [PK_Person] PRIMARY KEY CLUSTERED ([PersonID] ASC)
GO
ALTER TABLE [dbo].[Person] WITH CHECK ADD CONSTRAINT [CK_Person_GenderCode]
CHECK (([dbo].[IsValidCode]('Gender',[Gendercode])=(1)))
GO
IsValidCode может быть определен следующим образом:
CREATE FUNCTION [dbo].[IsValidCode]
(
@CodeTypeDescription NVARCHAR(40),
@Code INT
)
RETURNS BIT
AS
BEGIN
DECLARE @CodeType INT
DECLARE @Result BIT
SELECT @CodeType = Code
FROM dbo.Code
WHERE CodeType = 0 AND CodeDescription = @CodeTypeDescription
IF (@CodeType IS NULL)
BEGIN
SET @Result = 0
END
ELSE
BEGiN
IF EXISTS(SELECT * FROM dbo.Code WHERE CodeType = @CodeType AND Code = @Code)
SET @Result = 1
ELSE
SET @Result = 0
END
RETURN @Result
END
GO
Другая функция может быть создана для предоставления описания кода при запросе таблицы, в которой есть столбец кода. Вот пример запроса таблицы Person:
SELECT PersonID,
LastName,
FirstName,
GetCodeDescription('Gender',GenderCode) AS Gender
FROM Person
Все это было задумано с точки зрения предотвращения распространения справочных таблиц в базе данных и предоставления одной справочной таблицы. Я понятия не имею, будет ли этот дизайн хорошо работать на практике.
Я склоняюсь к использованию табличного представления для этого типа данных. В конечном счете, если вам нужно захватить данные, вам нужно будет их сохранить. Для целей отчетности лучше иметь место, откуда вы можете получить эти данные с помощью ключа. В целях нормализации я считаю, что одноразовые таблицы поиска проще, чем многоцелевые.
Тем не менее, перечисления работают очень хорошо для вещей, которые не изменятся, как пол и т. Д.