Действительно ли это - хорошая идея создать пользовательский тип для первичного ключа каждой таблицы данных?

У нас есть много кода, который передает о “Ids” строк данных; это главным образом ints или гуиды. Я мог сделать этот код более безопасным путем создания другой структуры для идентификатора каждой таблицы базы данных. Тогда средство проверки типа поможет найти случаи, когда неправильный идентификатор будет передан.

Например, таблица Person имеет вызовы столбца PersonId, и у нас есть код как:

DeletePerson(int personId)
DeleteCar(int carId)

Был бы это быть лучше иметь:

struct PersonId
{
   private int id;
   // GetHashCode etc....
}

DeletePerson(PersionId persionId)
DeleteCar(CarId carId)
  • Кто-либо получил реальный опыт донга это?

  • Действительно ли это стоит издержек?

  • Или больше боли тогда это стоит?

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


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

Обновление: Обратите внимание, что это не веб-приложение, и Ids сохранены в памяти и переданы о с WCF, таким образом, нет никакого преобразования в строки в краю. Нет никакой причины, что интерфейс WCF не может использовать тип PersonId и т.д., тип PersonsId и т.д. мог даже использоваться в коде UI WPF/Winforms.

Единственный по сути "невведенный" бит системы является базой данных.


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

11
задан Ian Ringrose 11 January 2010 в 21:52
поделиться

6 ответов

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

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

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

2
ответ дан 3 December 2019 в 09:20
поделиться

Вы можете просто выбрать GUID, как вы предложили себе. Тогда вам не придется беспокоиться о передаче идентификатора человека «42» для делекара () и случайно удалить автомобиль с ID 42. GUID являются уникальными; Если вы передаете лицо GUID для DELETECAR в вашем коде из-за программирования Typo, этот GUID не будет PK любого автомобиля в базе данных.

2
ответ дан 3 December 2019 в 09:20
поделиться

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

  1. Ваш код доступа к данным всегда работает, как вы ожидаете (т. Е. Вы не загружаете непоследовательную ключевую информацию в свои классы и получать неправильное использование из-за этого) Отказ
  2. То, что ваш код «Wrund Trip» работает как ожидалось (то есть, что загрузка записи, издавая изменение и сохранение его обратно, не каким-то образом повреждает ваши бизнес-логические объекты).

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

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

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

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

1
ответ дан 3 December 2019 в 09:20
поделиться

Вы можете создать простой ID Класс, который может помочь дифференцировать в коде между двумя:

public class Id<T>
{
    private int RawValue
    {
        get;
        set;
    }

    public Id(int value)
    {
        this.RawValue = value;
    }

    public static explicit operator int (Id<T> id) { return id.RawValue; }

    // this cast is optional and can be excluded for further strictness
    public static implicit operator Id<T> (int value) { return new Id(value); }
}

подобным образом используется так:

class SomeClass
{
     public Id<Person> PersonId { get; set; }
     public Id<Car> CarId { get; set; }
}

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

2
ответ дан 3 December 2019 в 09:20
поделиться

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

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

int personId;
if (Int32.TryParse(Request["personId"], out personId)) { 
    this.person = this.PersonRepository.Get(new PersonId(personId));
}

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

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

4
ответ дан 3 December 2019 в 09:20
поделиться

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

1
ответ дан 3 December 2019 в 09:20
поделиться
Другие вопросы по тегам:

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