понедельник, 1 апреля 2013 г.

Entity framework - StoreGeneratedPattern

Довольно стандартная ситуация, когда в качестве Primary Key в таблице БД SQL Server используется GUID (uniqueidentifier).
Выглядит это вот так:
CREATE TABLE [dbo].[Users]
(
    [ID] UNIQUEIDENTIFIER NOT NULL DEFAULT(NEWID()) PRIMARY KEY NONCLUSTERED,
    [Name] NVARCHAR(200) NOT NULL
)
В модели Entity framework выглядеть это будет вот как:



Теперь добавим новую запись в нашу таблицу:
var entities = new TestEntities();
var newUser = new User { Name = "TestUser" };
entities.Users.AddObject(newUser);
entities.SaveChanges();

В результате в Management Studio получаем такую картину:



Не смотря на Default constraint, получаем абсолютно пустой Guid. Оно и логично. Ведь он все же был передан как не Null со стороны Entity framework, так ведь?
И в моем случае я всегда решал эту проблему довольно просто:
var newUser = new User { ID = Guid.NewGuid(), Name = "TestUser2" };

Но это довольно таки не практичное решение, так как всегда нужно помнить про заполнение ID. Да и в конце концов, для чего еще Default constraint был создан на стороне SQL Server?

Немного покопавшись в возможностях Entity framework - нашел интересный параметр StoreGeneratedPattern.
Это обычное перечисление:
1. None - сервер не отвечает за генерацию значения. Зачастую - это значение по умолчанию.
2. Identity - значение генерируется при добавлении новой записи. Работает по умолчанию для колонок, где выбрано IDENTITY.
3. Computed - значение генерируется при добавлении либо изменении записи.

Если взглянете на первый скриншот в посте, то сможете найти там StoreGeneratedPattern для нашей колонки с ID.
Нам очень подошло бы поведение Identity. Очень жаль, что Entity framework-ом не смог это интерпретировать как Identity самостоятельно.

Ну да и ладно. Сделаем это сами. Идем в Conceptual Designer, и меняем StoreGeneratedPattern для ID на Identity.

Можете попробовать добавить запись снова. Все прошло хорошо? Тогда вам повезло и нужный апдейт уже есть на вашей машине.
Но не удивляйтесь, если все свалится с ошибкой в стиле: запись с таким же primary key уже существует. Почему? Скорее всего GUID снова пришел пустым. И если взглянуть на xml, который хранится в edmx файле, то в CSDL вы увидите:


А вот в SSDL это свойство не пробросилось:


Не беда, подумаю многие. И в целом это правда. Ничего не мешает нам добавить нужное свойство в XML руками. В итоге получится вот так:


Вот только в таком случае придется смириться с тем, что после обновления модели - весь это "кастомный" XML слетит и придется добавлять его заново. Писать свой класс, который будет это хэндлить тоже нет никакого интереса.

Погуляв немного по microsoft connect оказалось, что баг этот существует еще с далекого 2009-го года.И проявляется даже на 4.4 и 5 версии EF. Но радует, что есть фикс.
Скачать его можно отсюда. Перезагрузки не требует.

После установки все стало на свои места и работает как положено.

Удачи!