рекомендации по работе с кодом или таблицами подстановки

StackOverflow https://stackoverflow.com/questions/753460

Вопрос

[ОБНОВЛЕНИЕ] Выбранный подход приведен ниже, в качестве ответа на этот вопрос

Привет,

Я изучал эту тему, но на самом деле не могу найти то, что ищу...

Я имею в виду кодовые таблицы:такие вещи, как "морской статус", пол, конкретные правовые или социальные состояния...Более конкретно, эти типы имеют только заданные свойства, и элементы не собираются меняться в ближайшее время (но могли бы).Свойства - это идентификатор, имя и описание.

Мне интересно, как лучше всего справиться с этим в следующих технологиях:

  • в базе данных (несколько таблиц, одна таблица с разными кодовыми ключами ...?)

  • создание классов (вероятно, что-то вроде наследования ICode с помощью ICode.Имя и ICode.Описание)

  • создание представления / презентатора для этого:должен быть экран, содержащий их все, то есть список типов (пол, морской статус ...), а затем список значений для этого типа с именем и описанием для каждого элемента в списке значений.

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

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

[ПОСЛЕДУЮЩИЕ ДЕЙСТВИЯ]

Хорошо, я получил хороший ответ от CodeToGlory и Ahsteele.Давайте уточним этот вопрос.

Допустим, мы говорим не о поле или морском статусе, значения которых определенно не изменятся, а о "вещах", у которых есть Название и Описание, но не более того.Например:Социальные статусы, Правовые статусы.

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

Как это можно было бы обработать в View & Presenters?Я нахожу здесь трудность в том, что типы nameиdescription затем нужно было бы извлечь из имени класса?

ДБ:Каковы плюсы и минусы использования нескольких таблиц подстановки по сравнению с одной?

Это было полезно?

Решение 3

Я решил пойти по такому пути:

CodeKeyManager mgr = new CodeKeyManager();
CodeKey maritalStatuses = mgr.ReadByCodeName(Code.MaritalStatus);

Где:

  • CodeKeyManager может получать кодовые ключи из базы данных (CodeKey=MaritalStatus)
  • Code — это класс, наполненный константами, возвращающий строки, поэтому Code.MaritalStatus = «maritalStatus».Эти константы соответствуют таблице CodeKey > CodeKeyName.
  • В базе данных у меня есть 2 таблицы:
    • CodeKey с идентификатором, CodeKeyName
    • CodeValue с CodeKeyId, ValueName, ValueDescription

БД:

альтернативный текст http://lh3.ggpht.com/_cNmigBr3EkA/SeZnmHcgHZI/AAAAAAAAFU/2OTzmtMNqFw/codetables_1.JPG

Код класса:

public class Code
{
    public const string Gender = "gender";
    public const string MaritalStatus = "maritalStatus";
}

Кодовый ключ класса:

public class CodeKey
{
    public Guid Id { get; set; }
    public string CodeName { get; set; }

    public IList<CodeValue> CodeValues { get; set; }
}

Кодовое значение класса:

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) коды для удобства использования в бизнес-логике.

Спасибо за ответы!Если есть какие-либо замечания по этому подходу, пожалуйста!

Другие советы

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

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

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

Пара вещей здесь:

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

  2. Используйте таблицы поиска для элементов, которые не фиксированы, как указано выше, и могут изменяться, увеличиваться/уменьшаться с течением времени.

Очень типично иметь в базе данных таблицы поиска.Определите объект «ключ-значение» на своем бизнес-уровне, который может работать с вашим представлением/презентацией.

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

Тем не менее, перечисления очень хорошо работают для вещей, которые не меняются, например, пола и т. д.

Почему всем хочется усложнять кодовые таблицы?Да, их много, но они простые, поэтому оставьте их такими.Просто относитесь к ним, как к любому другому предмету.Они являются частью домена, поэтому моделируйте их как часть домена, ничего особенного.Если вы этого не сделаете, когда им неизбежно понадобятся дополнительные атрибуты или функциональность, вам придется отменить весь код, который в настоящее время их использует, и переработать его.

По одной таблице на курс (для ссылочной целостности и доступности для отчетов).

Для классов, конечно, опять же по одному на каждый, потому что если я напишу метод для получения объекта «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

Контрольное ограничение может быть добавлено к таблице кодов, чтобы гарантировать, что в таблицу введен допустимый кодовый тип:

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

Можно было бы создать другую функцию для предоставления описания кода при запросе таблицы, содержащей столбец code.Вот пример запроса таблицы Person:

SELECT PersonID,
    LastName,
    FirstName,
    GetCodeDescription('Gender',GenderCode) AS Gender
FROM Person

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top