Как Вы вводите или обновляете многих ко многим таблицам в платформе объекта .NET

Это кажется, что должно быть довольно очевидно, но что-то о платформе объекта смущает меня, и я не могу заставить это работать.

Вполне просто у меня есть три таблицы, где Значения идентификаторов являются столбцами идентификационных данных: Пользователи (идентификатор пользователя, имя пользователя) Категории (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.

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

5
задан GordonB 10 March 2010 в 13:18
поделиться

2 ответа

Вам нужно вызвать 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()

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

Если я посмотрю на хранилище EntityModel через обозреватель моделей, он показывает, что столбец CategoryId внутри JoinTable действительно имеет StoreGeneratedPattern, установленный на Identity, а UserId - на None. Почему EF сделал это на этапе генерации, когда присутствовал составной ПК, мне непонятно. Я опубликую ошибку об этом в MS, однако пока вы можете вручную отредактировать файл edmx / ssdl после генерации, чтобы удалить спецификатор идентичности. Найдите строку 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)
5
ответ дан 14 December 2019 в 13:35
поделиться

Было бы очень повезло найти ранее существовавшую библиотеку, которая готова разобрать предоставленное вами примерное выражение. Я рекомендую сделать ваш формат выражения немного более машиночитаемым, сохраняя при этом всю его ясность. S-выражение Лиспа (которое использует префиксную нотацию) компактно и ясно:

(и "президент" (или "рональд" "джордж" "салли"))

Написание синтаксического анализатора для этого формата проще, чем для вашего формата. Или вы можете просто переключиться на Lisp и он разберет его нативно.:)

Примечание: Я полагаю, вы не хотели сделать ваш оператор "НЕ" двоичным, верно?

-121--3397719-

Возможно, потребуется просмотреть код simpleBool.py на этой странице , использующей модуль анализа. В противном случае, вот простой код, который я написал.

Это не модуль, но он может привести вас в нужное русло.

def found(s,searchstr):
    return s.find(searchstr)>-1

def booltest1(s):
    tmp = found(s,'george') and not found(s,'bush')
    return found(s,'president') and (found(s,'ronald') or tmp)

print booltest1('the president ronald reagan')
print booltest1('george bush was a president')

и вы можете протестировать другие. Я использовал tmp, потому что линия становилась такой длинной

-121--3397721-

Я сделал это, чтобы сначала создать допустимую сущность категории с ключом сущности.

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

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

Category myCategory = new Category{CategoryID = categoryIDToUse };

Затем добавьте эту сущность в набор сущностей (CategureSet) в ObjectContext с помощью метода AttachTo (можно проверить, присоединена ли она). Затем можно добавить категорию к сущности пользователя с помощью метода Добавить. Что-то вроде этого:

myUser.Categories.Add(myCategory);

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

1
ответ дан 14 December 2019 в 13:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: