Entity Framework: "Заявление об обновлении, вставке или удалении повлияло на неожиданное количество строк (0)".

Я использую Entity Framework для заполнения элемента управления сеткой. Иногда, когда я делаю обновления, я получаю следующую ошибку:

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

Я не могу понять, как воспроизвести это. Но это может иметь какое-то отношение к тому, как близко я делаю обновления. Кто-нибудь видел это или кто-нибудь знает, что означает сообщение об ошибке?

Изменить: К сожалению, я больше не могу воспроизвести проблему, с которой я столкнулся, потому что я отступил от этого проекта и не помню, нашел ли я в конце концов решение, если другой разработчик исправил его, или если я работал вокруг него. Поэтому я не могу принять никаких ответов.

254
задан strongopinions 03 дек. '09 в 1:06
источник поделиться
42 ответов
  • 1
  • 2

Это побочный эффект функции, называемой оптимистичной concurrency.

Не 100% уверен, как включить или отключить его в Entity Framework, но в основном то, что он говорит вам, заключается в том, что между вами, когда вы извлекаете данные из базы данных, и когда вы сохранили изменения, кто-то другой изменил данные (что означало когда вы пошли, чтобы сохранить его, 0 строк действительно обновились). В терминах SQL их предложение update query where содержит исходное значение каждого поля в строке, и если 0 строк затронуты, он знает, что что-то пошло не так.

Идея заключается в том, что вы не закончите перезаписывать изменения, которые не было известно вашему приложению, - это в основном небольшая мера безопасности, которая была внесена .NET во все ваши обновления.

Если это согласовано, вероятность того, что это происходит в вашей собственной логике (EG: вы фактически обновляете данные самостоятельно в другом методе между выбором и обновлением), но это может быть просто условие гонки между двумя приложениями.

163
ответ дан fyjham 03 дек. '09 в 1:25
источник поделиться

Я столкнулся с этим, и это было вызвано тем, что поле идентификатора объекта (ключа) не было установлено. Таким образом, когда контекст пошел на сохранение данных, он не смог найти идентификатор = 0. Обязательно поместите точку останова в свой оператор обновления и убедитесь, что идентификатор объекта был установлен.

От комментария Пола Беллоры

У меня была эта точная проблема, вызванная забыванием включить скрытый идентификатор ввод на странице редактирования .cshtml

323
ответ дан webtrifusion 14 июня '11 в 2:59
источник поделиться

Ничего себе, много ответов, но я получил эту ошибку, когда сделал что-то немного другое, о чем не упоминал нигде.

Короче говоря, если вы создадите новый объект и сообщите 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);
80
ответ дан Ben 18 окт. '12 в 15:38
источник поделиться

Я столкнулся с такой же пугающей ошибкой...:) Тогда я понял, что забыл установить

@Html.HiddenFor(model => model.UserProfile.UserId)

для первичного ключа обновляемого объекта! Я стараюсь забыть простую, но очень важную вещь!

Кстати: HiddenFor для ASP.NET MVC.

21
ответ дан Leniel Macaferi 05 июня '12 в 7:58
источник поделиться

Проверьте, не забыл ли вы атрибут "DataKeyNames" в GridView. это необходимо при изменении данных в GridView

http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.datakeynames.aspx

16
ответ дан Solly 27 янв. '11 в 13:51
источник поделиться

Проблема вызвана одной из двух вещей: -

  • Вы пытались обновить строку с одним или несколькими свойствами Concurrency Mode: Fixed.., а Оптимистичный Concurrency не позволил сохранить данные. То есть. некоторые изменили данные строки между временем, когда вы получили данные сервера, и когда вы сохранили данные своего сервера.
  • Вы пытались обновить или удалить строку, но строка не существует. Другой пример того, кто-то меняет данные (в этом случае, удаляет) между восстановлением, затем сохраняет ИЛИ вы плоские, пытаясь обновить поле, которое не является идентификатором (т.е. StoreGeneratedPattern = Computed), и эта строка не существует.
13
ответ дан Pure.Krome 17 февр. '11 в 5:27
источник поделиться

У меня была та же проблема, я выяснил, что это было вызвано RowVersion, которая была нулевой. Убедитесь, что Идентификатор и RowVersion не нуль.

для получения дополнительной информации см. этот учебник

http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/handling-concurrency-with-the-entity-framework-in-an-asp-net-mvc-application

8
ответ дан Bilel Chaouadi 28 авг. '14 в 17:03
источник поделиться

У меня была такая же проблема, и @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; }
    }
}   
8
ответ дан Dhaust 23 янв. '12 в 5:17
источник поделиться

Во время редактирования включается идентификатор или первичный ключ объекта как скрытое поле в представлении

т

      @Html.HiddenFor(m => m.Id)

который решает проблему.

Кроме того, если ваша модель включает неиспользуемый элемент, включите это и отправьте это на контроллер

7
ответ дан Arun Aravind 05 дек. '12 в 10:21
источник поделиться

Вам нужно явно включить BoundField первичного ключа. Если вы не хотите, чтобы пользователь видел первичный ключ, вам нужно скрыть его с помощью css:

    <asp:BoundField DataField="Id_primary_key" ItemStyle-CssClass="hidden" 
HeaderStyle-CssClass="hidden" />

Где "hidden" - это класс в css, для которого установлено значение "none".

6
ответ дан Paulo 26 окт. '10 в 10:08
источник поделиться

Я также столкнулся с этой ошибкой. Проблема, которая, как оказалось, была вызвана триггером на таблице, которую я пытался сохранить. В Trigger используется "INSTEAD OF INSERT", что означает, что в эту таблицу вставлены 0 строк, следовательно, ошибка. К счастью, в случае, когда функция триггера была неправильной, но я предполагаю, что это может быть действительная операция, которая должна каким-то образом обрабатываться в коде. Надеюсь, это поможет кому-то в один прекрасный день.

5
ответ дан Si-N 24 июля '14 в 14:54
источник поделиться
  @Html.HiddenFor(model => model.RowVersion)

Моя rowversion была нулевой, поэтому пришлось добавить это в представление который решил мою проблему

4
ответ дан Prakash R 17 февр. '15 в 11:32
источник поделиться

Просто убедитесь, что таблица и форма имеют первичный ключ и edmx.

я обнаружил, что любые ошибки во время обновления обычно происходили из-за:  - Нет первичного ключа в таблице  - Нет первичного ключа в Редактировании вида/формы (например, @Html.HiddenFor(m=>m.Id)

4
ответ дан Moji 01 марта '13 в 16:55
источник поделиться

Я получил ту же ошибку, потому что часть PK была столбцом datetime, а вставляемая запись использовала DateTime.Now как значение для этого столбца. Структура Entity будет вставлять значение с точностью до миллисекунды, а затем искать значение, которое он только вставил, также с точностью до миллисекунды. Однако SqlServer округлил значение до второй точности, и, таким образом, инфраструктура сущности не смогла найти значение точности в миллисекундах.

Решением было усечение миллисекунд из DateTime.Now перед вставкой.

4
ответ дан innominate227 11 дек. '15 в 0:17
источник поделиться

У меня была та же проблема. В моем случае я пытался обновить первичный ключ, который не разрешен.

3
ответ дан ajaysinghdav10d 30 авг. '15 в 10:33
источник поделиться

Я получил эту ошибку, когда я удалял некоторые строки в БД (в цикле) и добавлял новые в ту же таблицу.

Решения для меня заключались в том, чтобы динамически создавать новый контекст в каждой итерации цикла

3
ответ дан Tony 20 авг. '12 в 14:53
источник поделиться

Одним из способов отладки этой проблемы в среде 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.

Не было идентификатора категории, идентифицированного идентификатором EF, отправленного в базу данных, поэтому пострадали 0 записей.

Это был не EF-недостаток, а скорее неправильный коллапс "??" выражение в диспетчере представлений, который посылал глупость до уровня данных.

2
ответ дан rism 29 янв. '14 в 5:48
источник поделиться

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

ИЛИ

Это также может произойти, если все назначенные свойства объекта были назначены с теми же значениями, что и раньше.

        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
        }
2
ответ дан Serj Sagan 23 нояб. '13 в 1:41
источник поделиться

Если вы пытаетесь создать сопоставление в вашем файле edmx в "функции Imports", это может привести к этой ошибке. Просто очистите поля для вставки, обновления и удаления, которые находятся в Картографических данных для данного объекта в вашем edmx, и он должен работать. Надеюсь, я дал понять.

2
ответ дан Mubarak 20 мая '11 в 23:34
источник поделиться

Я начал получать эту ошибку после перехода от первой модели к кодовой. У меня есть несколько потоков, обновляющих базу данных, где некоторые могут обновлять одну и ту же строку. Я не знаю, почему у меня не было проблемы с использованием model-first, предположим, что он использует другой concurrency по умолчанию.

Чтобы обрабатывать его в одном месте, зная условия, при которых это могло произойти, я добавил следующую перегрузку в класс 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), где это применимо.

2
ответ дан avenmore 11 дек. '14 в 17:39
источник поделиться

Ну, у меня такая же проблема. Но это было связано с моей собственной ошибкой. Фактически я сохранял объект вместо его добавления. Итак, это был конфликт.

2
ответ дан Ali 11 марта '14 в 20:06
источник поделиться
    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();
                }
        }
    }
1
ответ дан Prem Prakash 16 дек. '12 в 21:07
источник поделиться

Я столкнулся с этим с помощью Telerik RadGrid. У меня был первичный ключ как столбец с сеткой, который был установлен только для чтения. Это будет нормально работать, если столбец был отображен = "false", но readonly = "true" вызвало проблему. Я решил это, указав отображение столбца сетки = 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> 
1
ответ дан Talimite 25 нояб. '11 в 23:32
источник поделиться

У вас была такая же проблема.

Я использую EF 6, Code First + Migrations. Проблема заключалась в том, что наш администратор баз данных создал ограничение на таблицу, которая запустила ошибку.

1
ответ дан Jaime Yule 23 сент. '14 в 17:45
источник поделиться

Ни один из вышеперечисленных ответов не полностью охватил мою ситуацию и решение проблемы.

Код, в котором ошибка была указана в контроллере MVC5:

        if (ModelState.IsValid)
        {
            db.Entry(object).State = EntityState.Modified; 
            db.SaveChanges(); // line that threw exception
            return RedirectToAction("Index");
        }

Я получил это исключение, когда я сохранял объект в режиме редактирования. Причина, по которой это бросила, состояла в том, что, когда я вернулся, чтобы сохранить его, я изменил свойства, которые сформировали первичный ключ на объекте. Таким образом, установка его состояния в Modified не имела никакого смысла для EF - это была новая запись, а не ранее сохраненная.

Вы можете решить эту проблему либо A), чтобы изменить вызов сохранения, либо добавить объект, либо B) просто не изменяйте первичный ключ при редактировании. Я сделал B).

1
ответ дан J. Polfer 23 июня '16 в 18:15
источник поделиться

Когда принятый ответ сказал ", это не приведет к перезаписыванию изменений, которые ваше приложение не знало, произошло", я был скептичен, потому что мой объект был недавно создан. Но потом оказывается, что к таблице добавлен INSTEAD OF UPDATE, INSERT- TRIGGER, который обновлял вычисленный столбец той же таблицы.

Как только я изменил это на AFTER INSERT, UPDATE, он работал нормально.

1
ответ дан Mahesh 19 окт. '16 в 19:40
источник поделиться

У меня также была эта ошибка. Существуют ситуации, когда объект может не знать о фактическом контексте базы данных, который вы используете, или Модель может отличаться. Для этого установите: EntityState.Modified; в EntityState.Added;

Для этого:

if (ModelState.IsValid)
{
context.Entry(yourModelReference).State = EntityState.Added;
context.SaveChanges();
}

Это гарантирует, что Entity знает, что вы используете или добавляете состояние, с которым вы работаете. В этот момент необходимо установить все правильные значения модели. Осторожно, чтобы не потерять никаких изменений, которые могли быть сделаны в фоновом режиме.

Надеюсь, что это поможет.

0
ответ дан Rusty Nail 17 сент. '13 в 13:55
источник поделиться

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

context.Users.Attach(orderer);

с

if (orderer.Id > 0) {
    context.Users.Attach(orderer);
}
0
ответ дан Andrew 20 мая '13 в 17:21
источник поделиться

У меня была аналогичная проблема сегодня, я опишу ее здесь, так как это не совсем оптимистичная ошибка concurrency.

Я конвертирую старую систему в новую базу данных, и у нее есть несколько тысяч объектов, к которым я должен был script перейти в новую систему. Тем не менее, чтобы помочь с здравомыслием, я решил сохранить оригинальные уникальные идентификаторы и поэтому ввел это в новый объект, а затем попытался сохранить его.

Проблема заключалась в том, что я использовал MVC Scaffolding для создания базовых репозиториев, и у них есть шаблон в их методе UpdateOrInsert, который в основном проверяет, установлен ли атрибут Key перед тем, как он добавит новый объект или изменит его состояние изменено.

Поскольку Guid был установлен, он пытался изменить строку, которая на самом деле не существовала в базе данных.

Я надеюсь, что это поможет кому-то еще!

0
ответ дан Russ Clarke 13 мая '13 в 19:05
источник поделиться

У меня была проблема с идентификатором Mvc при регистрации нового пользователя, а не:

var result = await UserManager.CreateAsync(user);

Я делал:

var result = await UserManager.UpdateAsync(user);
0
ответ дан JustLearning 06 мая '17 в 13:42
источник поделиться
  • 1
  • 2

Другие вопросы по меткам или Задайте вопрос