Работа с идентификаторами в объектном дизайне - PullRequest
8 голосов
/ 17 мая 2011

Некоторое время я думал о том, как обращаться с объектами, которым база данных присваивает идентификаторы.

Типичный объект, представляющий табличную сущность, может выглядеть следующим образом:

public class Test
{
    public int Id { get; private set; }
    public string Something { get; set; }
}

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

Однако, если мы хотим вставить новый объект типа Test в базу данных, поле Id все равно должно иметь значение. Мы могли бы просто использовать «0», так как он вряд ли будет использоваться в качестве ключа базы данных, но на самом деле это не очень хороший дизайн.

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

Какие-нибудь хорошие идеи о том, как сделать хороший дизайн для этой проблемы?

Ответы [ 3 ]

3 голосов
/ 17 мая 2011

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

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

Вы всегда можете заключить свойства вашего объекта в отдельный класс, если чувствуете, что наличие объектов без ids, установленных в вашем приложении, проблематично. Вы будете использовать этот класс по существу только для переноса параметров для еще не созданного объекта (процесс создания завершается со вставкой в ​​базу данных). Как только объект вставлен, назначен идентификатор и прочее - вы можете работать со своей обычной сущностью. Будет ли ваш пользователь идти «О, хватит! Что это?» или «Хорошо ... Я знаю, что делать». однажды подошел id = 0?

Редактировать

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

3 голосов
/ 17 мая 2011

Нет ничего плохого в разработке класса, так что идентификатор 0 указывает, что объект еще не был сериализован. В прошлом я создавал системы, которые успешно использовали этот подход. Просто убедитесь, что эта семантика хорошо определена в вашем API, и что это значение соблюдается во всем коде.

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

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

С этим одним резервированием, этот дизайн должен нормально работать.

public class Test : IEquatable<Test>
{ 
    /// <summary>
    /// The unique identifier for this Test entity, or zero if this
    /// Test entity has not yet been serialized to the database.
    /// </summary>
    public int Id { get; private set; } 

    public string Something { get; set; }

    public override bool Equals(object obj)
    {
        return Equals(obj as Test);
    }

    public bool Equals(Test other)
    {
        if (other == null)
            return false;
        // Distinct entities may exist with the Id value of zero.
        if (Id == 0)
            return object.ReferenceEquals(this, other);
        return Id == other.Id;
    }

    /// <summary>
    /// Gets a hash code for this Test entity. Warning: an instance with
    /// an Id of zero will change its identity when saved to the DB. Use with care.
    /// </summary>
    /// <returns>The hash code.</returns>
    public override int GetHashCode()
    {
        return Id;
    }
} 
1 голос
/ 17 мая 2011

Итак, у вас есть класс, который содержит идентификатор таблицы базы данных в качестве поля, поэтому в случае поиска / удаления и обновления идентификатор вашей сущности выравнивается с идентификатором записи базы данных. В случае вставки вы можете получить идентифицирующее значение только что вставленной записи и обновить вашу сущность этим значением. Таким образом, вы можете иметь отдельные процедуры хранения для вставки / обновления / извлечения и удаления. SP вставки может вернуть вам идентификатор только что вставленной записи как out parameter. Надеюсь, я отвечу на ваш вопрос.

...