Entity Framework: "инструкция Store update, insert или delete повлияла на неожиданное количество строк (0)." [закрытый]
Я использую Entity Framework для заполнения элемента управления grid. Иногда, когда я делаю обновления я получаю следующую ошибку:
инструкция Store update, insert или delete затронула неожиданное количество строк (0). Объекты могут быть изменены или удалены с момента загрузки объектов. Обновить записи ObjectStateManager.
Я не могу понять, как воспроизвести это. Но это может иметь какое-то отношение к тому, как близко я делаю обновления. Имеет кто-нибудь видел это или кто-нибудь знает, что означает сообщение об ошибке?
Edit: к сожалению, я больше не могу воспроизвести проблему, с которой я столкнулся здесь, потому что я отошел от этого проекта и не помню, нашел ли я в конечном итоге решение, если другой разработчик исправил его, или если я работал вокруг него. Поэтому я не могу принять никаких ответов.
30 ответов:
это побочный эффект функции под названием оптимистический параллелизм.
не на 100% уверен, как включить/выключить его в Entity Framework, но в основном то, что он говорит вам, что между тем, когда вы захватили данные из базы данных, и когда вы сохранили свои изменения, кто-то другой изменил данные (что означало, когда вы пошли, чтобы сохранить его 0 строк на самом деле были обновлены). В терминах SQL, их
updateзапросwhereпредложение содержит исходное значение каждого поля в строке, и если 0 строки затронуты он знает, что что-то пошло не так.идея заключается в том, что вы не будете в конечном итоге перезаписывать изменения, о которых ваше приложение не знало, - это в основном небольшая мера безопасности, брошенная .NET на все ваши обновления.
Если это согласовано, скорее всего, это происходит в вашей собственной логике (например: вы на самом деле обновляете данные самостоятельно в другом методе между выбором и обновлением), но это может быть просто условие гонки между два приложения.
Я столкнулся с этим, и это было вызвано тем, что поле id (key) объекта не установлено. Таким образом, когда контекст пошел, чтобы сохранить данные, он не мог найти ID = 0. Обязательно поместите точку останова в инструкцию update и убедитесь, что задан идентификатор сущности.
из комментарий
У меня была эта точная проблема, вызванная тем, что я забыл включить скрытый идентификатор вход в систему .страница редактирования cshtml
Вау, много ответов, но я получил эту ошибку, когда я сделал что-то немного другое, что никто больше не упомянул.
короче говоря, если вы создадите новый объект и скажете EF, что его модифицировали с помощью
EntityState.Modifiedзатем он бросит эту ошибку, поскольку она еще не существует в базе данных. Вот мой код:MyObject foo = new MyObject() { someAttribute = someValue }; context.Entry(foo).State = EntityState.Modified; context.SaveChanges();Да, это кажется глупым, но это возникло потому, что метод, о котором идет речь, имел
fooперешел к нему создав ранее, теперь это только имеетsomeValueпередается ему и создаетfooсам по себе.легко исправить, просто замените
EntityState.ModifiedдоEntityState.Addedили измените всю эту строку на:context.MyObject.Add(foo);
я столкнулся с этой же пугающей ошибкой... :) Затем я понял, что забыл установить
@Html.HiddenFor(model => model.UserProfile.UserId)для первичного ключа объекта обновляется! Я склонен забывать эту простую, но очень важную вещь!
кстати:
HiddenForэто для ASP.NET MVC.
проверьте, не забыли ли вы атрибут "DataKeyNames" в GridView. это необходимо при изменении данных в GridView в
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.datakeynames.aspx
проблема вызвана одной из двух вещей :-
- вы пытались обновить строку с одним или несколькими свойствами
Concurrency Mode: Fixed.. и оптимистичный параллелизм не позволил сохранить данные. То есть. некоторые из них изменили данные строки между моментом получения данных сервера и моментом сохранения данных сервера.- вы попытались обновить или удалить строку, но строка не существует. Еще один пример того, как кто-то меняет данные (в данном случае удаляет) между ними получить затем сохранить или вы плоская наша попытка обновить поле, которое не является идентичностью (т. е.
StoreGeneratedPattern = Computed) и эта строка не существует.
Я получил эту же ошибку, потому что часть PK была столбцом datetime, а вставляемая запись использовала DateTime.Теперь в качестве значения для этого столбца. Entity framework будет вставлять значение с точностью до миллисекунды, а затем искать значение, которое он только что вставил, также с точностью до миллисекунды. Однако SqlServer округлил значение до второй точности, и поэтому Entity framework не смог найти значение точности миллисекунды.
решение было усечь миллисекунды от даты и времени.Теперь перед вставкой.
у меня была такая же проблема и @webtrifusion это ответ помог найти решение.
моя модель использовала
Bind(Exclude)атрибут идентификатора сущности, который вызывал значение идентификатора сущности равным нулю на HttpPost.namespace OrderUp.Models { [Bind(Exclude = "OrderID")] public class Order { [ScaffoldColumn(false)] public int OrderID { get; set; } [ScaffoldColumn(false)] public System.DateTime OrderDate { get; set; } [Required(ErrorMessage = "Name is required")] public string Username { get; set; } } }
У меня была та же проблема, я выяснил, что было вызвано RowVersion, который был null. Проверьте, что ваш Id и свой RowVersion are not null.
для получения дополнительной информации см. Этот учебник
при редактировании включите идентификатор или первичный ключ объекта в виде скрытого поля в представлении
ie
@Html.HiddenFor(m => m.Id)это решает проблему.
также, если ваша модель включает в себя неиспользуемый элемент, включите это тоже и опубликуйте это на контроллере
Я тоже наткнулся на эту ошибку. Проблема, как оказалось, была вызвана триггером на столе, который я пытался сохранить. Триггер использовал "вместо вставки", что означает, что 0 строк когда-либо вставлялись в эту таблицу, следовательно, ошибка. К счастью, в мае функциональность триггера была неправильной, но я думаю, что это может быть допустимая операция, которая должна каким-то образом обрабатываться в коде. Надеюсь, что это поможет кому-то однажды.
необходимо явно включить поле привязки первичного ключа. Если вы не хотите, чтобы пользователь видел первичный ключ, вы должны скрыть его с помощью css:
<asp:BoundField DataField="Id_primary_key" ItemStyle-CssClass="hidden" HeaderStyle-CssClass="hidden" />где 'hidden' - это класс в css, для которого установлено значение'none'.
Я начал получать эту ошибку после изменения модели-первый код-первый. У меня есть несколько потоков, обновляющих базу данных, где некоторые могут обновить одну и ту же строку. Я не знаю, почему у меня не было проблемы с использованием модели-во-первых, предположим, что он использует другой параллелизм по умолчанию.
чтобы обработать его в одном месте, зная условия, при которых это может произойти, я добавил следующую перегрузку в свой класс DbContext:
под названиемusing System.Data.Entity.Core.Objects; using System.Data.Entity.Infrastructure; public class MyDbContext: DbContext { ... public int SaveChanges(bool refreshOnConcurrencyException, RefreshMode refreshMode = RefreshMode.ClientWins) { try { return SaveChanges(); } catch (DbUpdateConcurrencyException ex) { foreach (DbEntityEntry entry in ex.Entries) { if (refreshMode == RefreshMode.ClientWins) entry.OriginalValues.SetValues(entry.GetDatabaseValues()); else entry.Reload(); } return SaveChanges(); } } }SaveChanges(true)где бы то ни было применимый.
@Html.HiddenFor(model => model.RowVersion)моя rowversion была null, поэтому пришлось добавить это в представление который решил мою проблему
строку
[DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.None)]сделал трюк в моем случае:using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; [Key] [DatabaseGenerated(DatabaseGeneratedOption.None)] public int? SomeNumber { get; set; }
просто убедитесь, что таблица и форма имеют первичный ключ и edmx обновлены.
Я обнаружил, что любые ошибки во время обновления, как правило, из-за: - Нет первичного ключа в таблице - Нет первичного ключа в виде/форме редактирования (например,
@Html.HiddenFor(m=>m.Id)
я получил эту ошибку спорадически при использовании
asyncметод. Не произошло с тех пор, как я переключился на синхронный метод.ошибки спорадически:
[Authorize(Roles = "Admin")] [HttpDelete] [Route("file/{id}/{customerId}/")] public async Task<IHttpActionResult> Delete(int id, int customerId) { var file = new Models.File() { Id = id, CustomerId = customerId }; db.Files.Attach(file); db.Files.Remove(file); await db.SaveChangesAsync(); return Ok(); }работает:
[Authorize(Roles = "Admin")] [HttpDelete] [Route("file/{id}/{customerId}/")] public IHttpActionResult Delete(int id, int customerId) { var file = new Models.File() { Id = id, CustomerId = customerId }; db.Files.Attach(file); db.Files.Remove(file); db.SaveChanges(); return Ok(); }
Я получил эту ошибку, когда я удалял некоторые строки в БД (в цикле), и добавление новых в той же таблице.
решения для меня были, чтобы динамично создавать новый контекст в каждой итерации цикла
public void Save(object entity) { using (var transaction = Connection.BeginTransaction()) { try { SaveChanges(); transaction.Commit(); } catch (OptimisticConcurrencyException) { if (ObjectStateManager.GetObjectStateEntry(entity).State == EntityState.Deleted || ObjectStateManager.GetObjectStateEntry(entity).State == EntityState.Modified) this.Refresh(RefreshMode.StoreWins, entity); else if (ObjectStateManager.GetObjectStateEntry(entity).State == EntityState.Added) Detach(entity); AcceptAllChanges(); transaction.Commit(); } } }
Если вы пытаетесь создать сопоставление в вашем файле edmx с "импортом функций", это может привести к этой ошибке. Просто очистите поля для вставки, обновления и удаления, которые находятся в сведениях о сопоставлении для данного объекта в вашем edmx, и он должен работать. Надеюсь, я ясно выразился.
У меня тоже была такая ошибка. В некоторых ситуациях сущность может не знать о фактическом контексте базы данных, который вы используете, или модель может отличаться. Для этого установите: EntityState.Изменено; для EntityState.Добавлено;
для этого:
if (ModelState.IsValid) { context.Entry(yourModelReference).State = EntityState.Added; context.SaveChanges(); }Это гарантирует, что сущность знает, что вы используете или добавляете состояние, с которым вы работаете. На этом этапе необходимо установить все правильные значения модели. Будьте осторожны, чтобы не потерять любые изменения, которые могли быть сделаны в фон.
надеюсь, что это помогает.
Это также произойдет, если вы пытаетесь вставить в уникальную ситуацию ограничения, т. е. если у вас может быть только один тип адреса для каждого работодателя, и вы пытаетесь вставить второй такой же тип с тем же работодателем, вы получите ту же проблему.
или
Это также может произойти, если все свойства объекта, которые были назначены, они были назначены с теми же значениями, что и раньше.
using(var db = new MyContext()) { var address = db.Addresses.FirstOrDefault(x => x.Id == Id); address.StreetAddress = StreetAddress; // if you are assigning address.City = City; // all of the same values address.State = State; // as they are address.ZipCode = ZipCode; // in the database db.SaveChanges(); // Then this will throw that exception }
Ну у меня такая же проблема. Но это было из-за моей собственной ошибки. На самом деле я сохранял объект вместо того, чтобы добавлять его. Так вот в чем был конфликт.
одним из способов отладки этой проблемы в среде Sql Server является использование SQL Profiler, входящего в состав вашей копии SqlServer, или при использовании Экспресс-версии получить копию Express Profiler бесплатно от CodePlex по следующей ссылке ниже:
С помощью SQL Profiler вы можете получить доступ к тому, что отправляется EF в БД. В моем случае это составляло:
exec sp_executesql N'UPDATE [dbo].[Category] SET [ParentID] = @0, [1048] = NULL, [1033] = @1, [MemberID] = @2, [AddedOn] = @3 WHERE ([CategoryID] = @4) ',N'@0 uniqueidentifier,@1 nvarchar(50),@2 uniqueidentifier,@3 datetime2(7),@4 uniqueidentifier', @0='E060F2CA-433A-46A7-86BD-80CD165F5023',@1=N'I-Like-Noodles-Do-You',@2='EEDF2C83-2123-4B1C-BF8D-BE2D2FA26D09', @3='2014-01-29 15:30:27.0435565',@4='3410FD1E-1C76-4D71-B08E-73849838F778' goя копирую вставил это в запрос окно в Sql Server и выполнил его. Конечно, хотя он работал, 0 записей были затронуты этим запросом, следовательно, ошибка возвращается EF.
в моем случае проблема была вызвана CategoryID.
не было никакого CategoryID, идентифицированного идентификатором EF, отправленным в базу данных, следовательно, затронуты 0 записей.
Это была не вина EF, а скорее багги нулевое слияние "??"заявление в контроллере Вида, который отправлял ерунду вниз к данным уровень.
ни один из приведенных выше ответов не вполне охватывал мою ситуацию и решение ее.
код, в котором ошибка была вызвана в контроллере MVC5:
if (ModelState.IsValid) { db.Entry(object).State = EntityState.Modified; db.SaveChanges(); // line that threw exception return RedirectToAction("Index"); }Я получил это исключение, когда я сохранял объект из вида редактирования. Причина, по которой он бросил его, заключалась в том, что когда я вернулся, чтобы сохранить его, я изменил свойства, которые сформировали первичный ключ на объекте. Таким образом, установка его состояния на Modified не имела никакого смысла для EF - это была новая запись, а не ранее кроме одного.
вы можете решить эту проблему, либо a) изменив вызов save, чтобы добавить объект, либо B) просто не изменяйте первичный ключ при редактировании. Я сделал Б).
Я столкнулся с этой проблемой в таблице, в которой отсутствовал первичный ключ и был столбец DATETIME(2, 3) (поэтому "первичный ключ" сущности был комбинацией всех столбцов)... При выполнении вставки метка времени имела более точное время (2018-03-20 08:29:51.8319154), которое было усечено до (2018-03-20 08:29:51.832), поэтому поиск по ключевым полям не выполняется.
я столкнулся с этой помощью Telerik RadGrid по. У меня был первичный ключ в виде привязанного к сетке столбца, который был настроен только для чтения. Он будет работать нормально, если столбец display="false", но readonly="true" вызвал проблему. Я решил это, имея привязанный к сетке столбец display=false и добавив отдельный столбец шаблона для отображения
<telerik:GridBoundColumn HeaderText="Shouldnt see" Display="false" UniqueName="Id" DataField="Id"> </telerik:GridBoundColumn> <telerik:GridTemplateColumn HeaderText="Id" UniqueName="IdDisplay"> <ItemTemplate> <asp:Label ID="IDLabel" runat="server" Text='<%# Eval("Id") %>'></asp:Label> </ItemTemplate> </telerik:GridTemplateColumn>
Я получил это исключение, когда присоединение объекта, который не существует в базе данных. Я предположил, что объект был загружен из отдельного контекста, но если это был первый раз, когда пользователь посещает сайт, объект был создан с нуля. У нас есть автоинкрементные первичные ключи, поэтому я мог бы заменить
context.Users.Attach(orderer);С
if (orderer.Id > 0) { context.Users.Attach(orderer); }
Это может произойти при попытке обновить запись с идентификатором, который не существует в базе данных.
Comments