Как вы вставляете или обновляете таблицы "много ко многим" в .net entity Framework

StackOverflow https://stackoverflow.com/questions/2243618

Вопрос

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

Проще говоря, у меня есть три таблицы, где значения Id являются столбцами идентификаторов:Пользователи (userId, имя пользователя) Категории (CategoryID, CategoryName) Объединяемый (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.

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

Это было полезно?

Решение

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

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

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

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

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

Изменение:

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

Для:

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

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

insert [dbo].[JoinTable]([UserId], [CategoryId]) values (@0, @1)

Другие советы

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

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

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

Category myCategory = new Category{CategoryID = categoryIDToUse };

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

myUser.Categories.Add(myCategory);

Вызовите SaveChanges().У меня это сработало.

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

Перейдите по этой ссылке:http://nileshhirapra.blogspot.in/2012/03/entity-framework-insert-operation-with.html

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top