Как вы вставляете или обновляете множество таблиц в инфраструктуру сущностей .net? - PullRequest
5 голосов
/ 11 февраля 2010

Кажется, это должно быть совершенно очевидно, но что-то в структуре сущностей сбивает меня с толку, и я не могу заставить это работать.

Проще говоря, у меня есть три таблицы, в которых значения Id являются столбцами идентификаторов: Пользователи (userId, username) Категории (categoryId, categoryName) Составной элемент JoinTable (UserId, CategoryId).

В конструкторе сущностей (это .net 4.0), когда я импортирую эти таблицы, как и ожидалось, таблица соединения не появляется, но пользователи и категории показывают связь. Следующий код:

var _context = new MyContext();
var myUser = new User();
myUser.UserName = "joe";

var myCategory = new Category();
myCategory.CategoryName = "friends";

_context.Users.AddObject(myUser);  
myUser.Categories.Add(myCategory);

var saved = _context.SaveChanges();

Возвращает ошибку (хотя в базу данных ничего не добавлено):

An item with the same key has already been added.

Если я добавлю следующее перед сохранением:

_context.Categories.AddObject(myCategory);
myCategory.Users.Add(myUser);

Я получаю ту же ошибку и ничего не сохраняется в БД. Если я сохраню объекты myUser и myCategory до того, как попытаюсь их связать, они оба сохранятся, но при втором сохранении выдается ошибка, и в таблицу соединений ничего не добавляется:

Cannot insert the value NULL into column 'UserId', table '...dbo.JoinTable'; column does not  allow nulls. INSERT fails. The statement has been terminated.

Я явно не понимаю, сколько вставлено много отношений. Чего мне не хватает?

Ответы [ 3 ]

5 голосов
/ 26 февраля 2010

Вам необходимо вызвать SaveChanges () после добавления в базу данных объектов User и Category, а затем установить связь между ними.

Однако настоящая проблема здесь - второе исключение, которое вы перечислили. Если вы посмотрите на SqlProfiler или ADO.NET profiler в отладчике, вы увидите, что во время второго вызова SaveChanges это выглядит примерно так:

insert [dbo].[JoinTable]([UserId]) values (@0) select [CategoryId] from
[dbo].[JoinTable] where @@ROWCOUNT > 0 and [UserId] = @0 and [CategoryId] = scope_identity()

Очевидно, что это не сработает, если вы правильно запрограммировали свой JoinTable (составной PK на обоих столбцах).

Если я посмотрю на хранилище EntityModel через Обозреватель моделей, оно показывает, что столбец CategoryId внутри JoinTable действительно имеет для StoreGeneratedPattern значение Identity, а для UserId значение None. Почему EF сделал это на этапе генерации, когда присутствовал композитный ПК, мне не понятно. Я буду публиковать сообщение об ошибке в MS, однако в то же время вы можете вручную отредактировать файл edmx / ssdl после генерации, чтобы удалить спецификатор Identity. Найдите строку StoreGeneratedPattern = "Identity" в теге Property тега EntityType для JoinTable и удалите ее:

Изменение:

<Property Name="CategoryId" Type="int" Nullable="false" StoreGeneratedPattern="Identity" />

Кому:

<Property Name="CategoryId" Type="int" Nullable="false" />

Тогда, когда вы запустите свой код, вы получите намного лучший запрос на вставку (и больше никаких исключений!):

insert [dbo].[JoinTable]([UserId], [CategoryId]) values (@0, @1)
1 голос
/ 11 февраля 2010

Способ, которым я это сделал, - сначала создать действительный объект Category с ключом объекта.

Category myCategory = _context.Categories.First(i => i.CategoryID == categoryIDToUse);

Или вы можете попытаться создать объект в качестве заглушки, чтобы сохранить попадание в БД:

Category myCategory = new Category{CategoryID = categoryIDToUse };

Затем добавьте эту сущность в набор сущностей (CategorySet) на ObjectContext, используя метод AttachTo (вы можете проверить, если он уже присоединен).Затем вы можете добавить категорию в свой пользовательский объект, используя метод Add.Примерно так:

myUser.Categories.Add(myCategory);

Вызов SaveChanges ().Это сработало для меня.

0 голосов
/ 05 марта 2012

Когда новый родительский объект добавляется в Context, состояние всех объектов в дереве объектов изменяется на Добавленный, и, следовательно, EF пытается сохранить все такие объекты как новую запись.

Ссылка на эту ссылку: http://nileshhirapra.blogspot.in/2012/03/entity-framework-insert-operation-with.html

...