вставка с использованием linq-to-entities

Привет, у меня проблемы с устранением этой ошибки. Любая помощь по проблеме будет высоко оценена, спасибо!

Сообщение об ошибке:

Оператор обновления, вставки или удаления хранилища затронул непредвиденное количество строк (0). Объекты могли быть изменены или удалены после загрузки объектов. Обновите записи ObjectStateManager.

Всякий раз, когда я пытаюсь добавить ноутбук/рабочий стол, я получаю указанное выше сообщение об ошибке.
Все работает нормально при локальном запуске, но не на dev. Веб-сайт и служба/база данных находятся на двух разных устройствах разработки.

Tables:
Computer: ComputerID, UserID, HardwareName, Brand, IsDefaultDevice
Desktop: ComputerID,  MonitorWidth
Laptop: ComputerID, BatteryLife

generated sql:
exec sp_executesql N'insert [ScratchPad].[Computer]([UserID], [ComputerName], [Brand], [IsDefaultDevice])
values (@0, @1, @2, @3)
select [ComputerID]
from [ScratchPad].[Computer]
where @@ROWCOUNT > 0 and [ComputerID] = scope_identity()',N'@0 bigint,@1 nvarchar(19),@2 int,@3 bit',@0=2,@1=N'Computer666',@2=1,@3=0


using(var context = new MyDatabaseEntities())
{
       User user = context.Users.FirstOrDefault(x => x.UserID == userId);
       entityToAdd.User = user;
       bool hasOthers = context.Computers.Any(x=>x.User.UserID == userId);
       if(!hasOthers && !entityToAdd.IsDefaultDevice)
            entityToAdd.IsDefaultDevice = true;
       entityToAdd.BrandReference.EntityKey = Brand.GetDellProviderKey();
       context.AddToComputers(entityToAdd);
       context.SaveChanges();
}

Вот трассировка стека:

Во время выполнения текущего веб-запроса возникло необработанное исключение. Информацию о происхождении и расположении исключения можно определить с помощью приведенной ниже трассировки стека исключений.

Трассировки стека:

[FaultException`1: Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.]
   System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) +10259418
   System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) +539
   myWebPortal.Repositories.UserServiceRef.IUserService.AddComputer(Int64 userId, Computer toAdd) +0
   myWebPortal.Repositories.UserServiceRef.UseServiceClient.AddComputer(Int64 userId, Computer toAdd) in c:\users\katelyn\documents\my web project\myWebPortal.repositories\service references\userserviceref\reference.cs:1282
   myWebPortal.Repositories.UserAccountRepository.AddComputer(Int64 userId, Computer computer) in C:\Users\katelyn\Documents\my Web Project\myWebPortal.Repositories\UserRepository.cs:238
   myWebPortal.Web.Controllers.ComputerController.AddComputer(ComputerModel model) in C:\Users\katelyn\Documents\my Web Project\myWebPortal.Web\Controllers\ComputerController.cs:71
   lambda_method(ExecutionScope , ControllerBase , Object[] ) +69
   System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +236
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +31
   System.Web.Mvc.<>c__DisplayClassd.<InvokeActionMethodWithFilters>b__a() +85
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation) +632195
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +288
   System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +630660
   System.Web.Mvc.Controller.ExecuteCore() +125
   System.Web.Mvc.<>c__DisplayClass8.<BeginProcessRequest>b__4() +48
   System.Web.Mvc.Async.<>c__DisplayClass1.<MakeVoidDelegate>b__0() +21
   System.Web.Mvc.Async.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _) +15
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +85
   System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +51
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +454
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +263

Также при попытке добавить ноутбук/рабочий стол иногда вставлялась строка «Компьютер», но не строка «Ноутбук/рабочий стол».


person user283802    schedule 01.03.2010    source источник
comment
Вы никогда не увидите OptimisticConcurrencyException, если у вас нет поля, где ConcurrencyMode равно Fixed. Вы не показываете этого и не показываете код, который компилируется, или сгенерированный SQL. Если вам нужна помощь, вы должны предоставить реальный код и модель, которые вы используете, а не выдуманный пример, который, по вашему мнению, может отражать то, что вы делаете.   -  person Craig Stuntz    schedule 01.03.2010
comment
У меня нигде не установлен ConcurrencyMode. Я думаю, что это OptimisticConcurrencyException, так как оно перехвачено в блоке catch(OptimisticConcurrencyException e). И это настоящий код. А что сгенерировало SQL? Извините, новичок во всем этом здесь и просто пытаюсь поиграть с linq-to-entities.   -  person user283802    schedule 01.03.2010
comment
Нет, блок catch не может изменить тип исключения, если только он не выдает совершенно новое исключение (и я предполагаю, что вы проверили это). Если вы видите OptimisticConcurrencyException, значит где-то в каком-то поле ConcurrencyMode установлено на Fixed. Эта функция предназначена для управления оптимистичным параллелизмом с помощью, например, столбца SQL Server TIMESTAMP. Чтобы просмотреть SQL, сгенерированный EF, используйте SQL Profiler. Это покажет вам оператор UPDATE, который должен пояснить, почему он на самом деле не обновляет никаких данных.   -  person Craig Stuntz    schedule 01.03.2010
comment
Спасибо. Я добавил сгенерированный SQL и отредактировал свой код, чтобы сделать концепцию более понятной.   -  person user283802    schedule 02.03.2010
comment
Я все еще не вижу проблемы - то, что вы делаете в исправленном коде, выглядит нормально. Можете ли вы добавить трассировку стека для исключения?   -  person Craig Stuntz    schedule 02.03.2010
comment
Только что добавил трассировку стека, спасибо.   -  person user283802    schedule 02.03.2010
comment
Спасибо, но это трассировка вашего веб-приложения. Мне кажется, вы переключаетесь на другой процесс. Исключение выбрасывается там, так что это стек, на который нам нужно взглянуть. Еще одна вещь, которую нужно попробовать, — выполнить этот INSERT SQL в SQL Server Management Studio и посмотреть, сообщает ли он об изменении 1 строки (так и должно быть).   -  person Craig Stuntz    schedule 02.03.2010


Ответы (2)


Где вы создаете/инициализируете entityToAdd?

Можете ли вы подтвердить ограничения внешнего ключа и информацию о первичном ключе (автоинкремент, тип и т. д.). Кажется, что вставка по какой-то причине завершается с ошибкой, которая определяется неправильным количеством затронутых строк.

попробуйте запустить SQL самостоятельно из консоли управления SQL - вы получаете какие-либо ошибки? запись правильно вставлена?

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

person Basic    schedule 20.09.2010
comment
Была аналогичная проблема, за тем же исключением. Моя проблема была в триггере. Tnx - person 100r; 02.02.2011
comment
@ 100r - я тоже сталкиваюсь с этой ошибкой. Как вы решили проблему с триггером. - person muruge; 18.06.2011
comment
@muruge Проблема в том, что EF пытается отслеживать состояние объекта и управлять им. Триггеры изменяют состояние в базе данных, но не в кеше EF, что приводит к несоответствию, которое позже может вызвать ошибки. Самый простой способ обойти это - реализовать триггер в вашем DAL/BL в зависимости от причины. Таким образом, все изменения выполняются через объекты. Если вы хотите опубликовать вопрос с некоторыми подробностями вашей проблемы и дать нам ссылку, мы постараемся помочь с альтернативным подходом. К вашему сведению. Можно расширить контекст объекта, чтобы перехватывать такие события, как SavingChanges, которые могут вам пригодиться. - person Basic; 18.06.2011
comment
@Basiclife - я нашел решение по следующей ссылке. stackoverflow.com/questions/5820992/ - person muruge; 21.06.2011
comment
@muruge Tэто хороший обходной путь, чтобы обмануть его, заставив думать, что он выполнил только ту работу, для которой он был предназначен - может быть интересно получить запись, измененную триггером, до того, как триггер сработает, запустить ваш запрос, а затем получить ту же запись снова - есть вероятность, что 2-й вызов через EF не будет включать изменения, внесенные триггером. Я не уверен, но вы, вероятно, захотите проверить это до смерти, прежде чем использовать его в производстве. - person Basic; 22.06.2011
comment
@muruge Извините, хотел поблагодарить вас за то, что вы указали мне на этот ответ - очень интересно - ура :) - person Basic; 22.06.2011

Я сталкивался с той же проблемой раньше, и она была вызвана триггером INSTEAD OF в SQL Server. Мне кажется, что OptimisticConcurrencyExceptions возникают, когда SQL Server сообщает, что запрос выполнен успешно, но выполняемая инструкция SELECT не возвращает ожидаемое количество строк.

@mrunge предоставил ссылку на решение, которое я разместил для этой проблемы в комментариях к ответу @BasicLife.

Другая возможная причина — хранимая процедура, которая используется для вставок и обновлений вашей сущности. Из http://msdn.microsoft.com/en-us/library/bb738618.aspx:

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

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

person Ryan Gross    schedule 22.06.2011