Это кажется, что должно быть довольно очевидно, но что-то о платформе объекта смущает меня, и я не могу заставить это работать.
Вполне просто у меня есть три таблицы, где Значения идентификаторов являются столбцами идентификационных данных: Пользователи (идентификатор пользователя, имя пользователя) Категории (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.
Мне ясно не удается понять, сколько ко многим отношениям вставляется. Что я пропускаю?
Вам нужно вызвать 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)
Было бы очень повезло найти ранее существовавшую библиотеку, которая готова разобрать предоставленное вами примерное выражение. Я рекомендую сделать ваш формат выражения немного более машиночитаемым, сохраняя при этом всю его ясность. 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 (). Это сработало для меня.