Работа с идентификаторами в дизайне объекта сущности

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

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

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

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

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

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

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


person DEHAAS    schedule 17.05.2011    source источник
comment
невозможно получить объект без идентификатора, если он был извлечен из базы данных .. когда вы вставляете его, он немедленно получит идентификатор (если у вас нет какой-то действительно странной базы данных)   -  person xs0    schedule 17.05.2011
comment
@ xs0 Очевидно. Однако, если строго смотреть на определение типа объекта, это возможно.   -  person DEHAAS    schedule 17.05.2011
comment
Ну, вы в своем вопросе говорите обратное .. Но что вы хотите делать с этими объектами? Пока вы не объясните, какие операции с ними будут делать, непонятно, в чем проблема.   -  person xs0    schedule 17.05.2011
comment
Вы используете Entity Framework или имели в виду сущность в общем смысле?   -  person Tim    schedule 17.05.2011
comment
Я имею в виду сущность в общем смысле, хотя проблема, очевидно, существует и при использовании Entity Framework.   -  person DEHAAS    schedule 17.05.2011


Ответы (3)


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

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

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

Изменить

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

person k.m    schedule 17.05.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;
    }
} 
person Jeffrey L Whitledge    schedule 17.05.2011
comment
Я понимаю, что идентификатор 0, указывающий на то, что объект не имеет идентификатора, безусловно, является допустимым рабочим решением; Мне просто было интересно, можно ли сделать что-нибудь лучше. Я считаю, что всегда лучше не допускать неверных данных и документировать свой выход из них, чем не допускать, чтобы это было вообще возможно. - person DEHAAS; 18.05.2011
comment
@DEHAAS - Да, это был один из вариантов вашего исходного вопроса. Я просто сказал, что, на мой взгляд, это нормально. Я не вижу разницы между определением 0 как несохраненного и таким способом определения нуля, за исключением того, что первое - немного меньше проблем, чем второе. На мой взгляд, правильное документирование и реализация особой ценности - хорошее решение. - person Jeffrey L Whitledge; 18.05.2011
comment
@DEHAAS - Подумайте об этом: в double первый бит интерпретируется, чтобы указать, является ли числовое значение положительным или отрицательным. Однако он немного похож на любой другой и может интерпретироваться другими способами в других контекстах. Определение определенных комбинаций битов как означающих одно в отличие от другого является основной частью программирования и не указывает на плохой дизайн. - person Jeffrey L Whitledge; 18.05.2011

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

person FIre Panda    schedule 17.05.2011
comment
Я согласен с утверждением Абдула, что база данных несет ответственность за определение новых значений идентификаторов и установку любых других значений по умолчанию, подходящих для новых записей. Вам нужно запросить новую строку из базы данных, а затем разрешить пользователю изменять новую строку, если они хотят. - person Beth; 17.05.2011
comment
Конечно, объекту будет назначен идентификатор после того, как он будет вставлен в базу данных, и этот идентификатор может быть установлен для вставляемого объекта. Однако я все еще вижу проблему с представлением объекта до присвоения идентификатора. - person DEHAAS; 18.05.2011
comment
Так в чем проблема, которую вы видите? - person FIre Panda; 18.05.2011