Совет: Идентификация SQL Server и ключи уникального идентификатора при использовании Entity Framework

Я занимаюсь разработкой довольно сложной системы. Одной из наших основных задач является поддержка одноранговой репликации SQL Server. Идея состоит в том, чтобы поддерживать несколько географически разделенных узлов.

Второстепенной проблемой было использование современного ORM на среднем уровне. Нашим первым выбором всегда был Entity Framework, главным образом потому, что разработчикам нравится работать с ним. (Им нравится поддержка LiNQ.)

Итак, вот проблема:

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

Однако оказывается, что текущая версия Entity Framework имеет очень странное ограничение: если ключевой столбец сущности является уникальным идентификатором (GUID), то его нельзя настроить для использования значения по умолчанию (newsequentialid()), предоставленного базой данных. Уровень приложения должен сгенерировать GUID и заполнить значение ключа.

Итак, вот обсуждение:

  1. abandon Entity Framework and use another ORM:
    • use NHibernate and give up LiNQ support
    • использовать linq2sql и отказаться от поддержки в будущем (не говоря уже о привязке к SQL Server в БД)
  2. отказаться от GUID и использовать другую стратегию PK
  3. разработать метод генерации последовательных идентификаторов GUID (COMB?) на прикладном уровне.

Я склоняюсь к варианту 1 с linq2sql (моим разработчикам очень нравится linq2[stuff]) и 3. Это в основном потому, что я несколько не знаком с альтернативными ключевыми стратегиями, которые поддерживают схему репликации, к которой мы стремимся, и в то же время сохраняем здравомыслие. точка зрения разработчика.

Любое понимание или мнение будет принята с благодарностью.


person Curtis Batt    schedule 02.03.2009    source источник
comment
Сработало ли удостоверение в качестве ключа кластеризации? Я думаю, что во время репликации будут какие-то коллизии.   -  person Turnkey    schedule 17.08.2009
comment
Без вопросов. Ключ кластеризации не реплицируется; это бессмысленное значение, используемое механизмом БД для поддержания кластеризованного индекса в таблице.   -  person Curtis Batt    schedule 05.10.2009


Ответы (6)


Другой вариант (недоступный на момент публикации) — обновить до EF 4, который поддерживает идентификаторы GUID, созданные сервером.

person Craig Stuntz    schedule 24.05.2010
comment
Спасибо, что опубликовали это и напомнили мне, что EF 4 доступен. Слишком поздно для меня, чтобы переключиться сейчас (я больше не работаю там, где это было проблемой), но это звучит как лучшее решение с этого момента. (Хотя ваше предыдущее предложение сработало просто отлично. Кстати, спасибо.) - person Curtis Batt; 27.05.2010

Я поддерживаю предложение Крейга - вариант 4.

Вы всегда можете использовать столбец GUID, заполненный средним уровнем, в качестве ПЕРВИЧНОГО КЛЮЧА (это ЛОГИЧЕСКАЯ конструкция).

Чтобы избежать массивной фрагментации индекса (таким образом: таблицы), используйте какой-либо другой ключ (в идеале столбец INT IDENTITY) в качестве КЛАСТЕРИРУЮЩЕГО КЛЮЧА - это физическая конструкция базы данных, которую МОЖЕТ отделить от первичного ключа.

По умолчанию первичный ключ является ключом кластеризации, но это не обязательно. На самом деле, я улучшил производительность и резко снизил фрагментацию, сделав то же самое с базой данных, которую я «унаследовал» — добавил столбец INT IDENTITY и поместил ключ кластеризации в этот маленький, постоянно увеличивающийся, никогда не меняющийся INT — работает как шарм!

Марк

person marc_s    schedule 03.03.2009
comment
В ПОРЯДКЕ. Это звучит нормально. Я попробую. Спасибо. - person Curtis Batt; 03.03.2009

Хм? Я думаю, что ваши три варианта - ложный выбор. Рассмотрим вариант 4:

4) Используйте Entity Framework с непоследовательными идентификаторами GUID, созданными клиентом.

Конечно, EF не может видеть GUID, сгенерированные сервером БД, для новых строк, вставленных самой платформой, но вам не нужно генерировать GUID на сервере БД. Вы можете сгенерировать их на клиенте при создании экземпляров сущности. Весь смысл GUID в том, что не имеет значения, где вы его создаете. Что касается GUID, сгенерированных реплицированной БД, то EF увидит их нормально.

Ваши идентификаторы GUID на стороне клиента не будут последовательными (используйте Guid.NewGuid()), но они будут гарантированно уникальными во всем мире.

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

person Craig Stuntz    schedule 03.03.2009
comment
И создание последовательных руководств на клиенте, которые, если бы они работали на веб-сервере, в любом случае были бы одним и тем же полем, не так уж сложны. - person Craig; 03.03.2009
comment
Действительно случайные идентификаторы GUID приводят к фрагментации таблиц и разбиению страниц, что, в свою очередь, снижает производительность. Я нашел несколько статей о создании достойных последовательных GUID на среднем уровне. Похоже, это лучший вариант на данный момент. - person Curtis Batt; 03.03.2009
comment
Массовая фрагментация таблицы произойдет только в том случае, если вы также установите CLUSTERING KEY в столбце GUID. Вы не ДОЛЖНЫ, хотя! Вы можете сохранить ПЕРВИЧНЫЙ КЛЮЧ в столбце GUID и использовать постоянно увеличивающийся столбец IDENTITY в качестве КЛАСТЕРИРУЮЩЕГО КЛЮЧА --> ни о какой фрагментации не может быть и речи! - person marc_s; 03.03.2009
comment
Верно, Марк. Это также дает вам более привлекательный альтернативный ключ для использования в URI. - person Craig Stuntz; 03.03.2009
comment
@Craig, это также дает вам легко «подделку» ключа для URI :) - person Adam Tuliper - MSFT; 08.07.2011
comment
Что сказал Адам - ​​использование предсказуемого идентификатора в первую очередь побеждает цель использования GUID. - person annakata; 07.01.2013
comment
@annakata и Адам, я бы сказал, что секретов в URI нет. ИМХО цель GUID - децентрализовать создание уникальных идентификаторов. Защита прямых ссылок на объекты должна обеспечиваться аутентификацией и авторизацией, а не скрытыми URI. - person Craig Stuntz; 07.01.2013

Почему бы не использовать столбец идентификаторов? Если вы выполняете репликацию слиянием, вы можете запустить каждую систему с отдельного начального числа и работать в одном направлении (например, узел a начинается с 1 и добавляет 1, узел b начинается с 0 и вычитает один)...

person Community    schedule 03.03.2009
comment
Я действительно пытаюсь избежать этого. Я знаю, что это работает, но... меня это огорчает. SQL Server 2005 полностью подготовлен со своей причудливой функцией NewSequentialId(), а MS так увлечена своей причудливой новой Entity Framework. Но соедините их вместе, и пуф вы вернулись в 1999 год. - person Curtis Batt; 03.03.2009
comment
Это здорово, пока вы не переполняете тип данных. Или семя сбрасывается, и в ваших идентификаторах есть пробелы. Или вам нужно делать вставки в синхронизированные, физически отдельные базы данных и объединять их. (Что касается доставки журналов и других внештатных взломов). Больше нет веской причины использовать целочисленный идентификатор. - person 3Dave; 23.03.2010

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

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

Пошаговый пример приведен по адресу http://blogs.msdn.com/bags/archive/2009/03/12/entity-framework-modeling-action-stored-procedures.aspx, что довольно просто.

person Malcolm    schedule 06.04.2009

используйте newseqid с вашим собственным orm (это не так сложно) с linq

person Community    schedule 07.05.2009