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

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

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

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

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

Ответ 1

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

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

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

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

Ответ 2

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

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

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

Ответ 3

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

Короче говоря, если вы создадите новый объект и сообщите 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);

Ответ 4

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

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

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

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

Ответ 6

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

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

Ответ 7

У меня была такая же проблема, и @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

У меня была та же проблема, я выяснил, что это было вызвано 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

Ответ 9

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

т

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

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

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

Ответ 10

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

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

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

Ответ 11

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

Ответ 12

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

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

Ответ 13

  @Html.HiddenFor(model => model.RowVersion)

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

Ответ 14

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

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

Ответ 15

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

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

Ответ 16

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

Ответ 17

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

Ответ 18

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

ИЛИ

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

        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
        }

Ответ 19

Одним из способов отладки этой проблемы в среде 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-недостаток, а скорее неправильный коллапс "??" выражение в диспетчере представлений, который посылал глупость до уровня данных.

Ответ 20

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

Ответ 21

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

Ответ 22

Я столкнулся с этим с помощью 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> 

Ответ 23

    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();
                }
        }
    }

Ответ 24

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

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

Ответ 25

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

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

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

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

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

Ответ 26

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

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

Ответ 27

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

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

Мы решили это, проверив значение свойства и назначая только новое, если оно отличается.

Ответ 28

Получите эту ошибку при использовании SaveChanges (false), а затем позже SaveChanges() в том же контексте, в unitofwork, где несколько строк были удалены из двух таблиц (в контексте) (SaveChanges (False) был в одном из Затем в вызывающей функции вызывается SaveChanges(). Решение заключалось в том, чтобы удалить ненужные SaveChanges (false).

Ответ 29

Я выброшу это на случай, если кто-то столкнется с этой проблемой при работе в параллельном цикле:

Parallel.ForEach(query, deet =>
{
    MyContext ctx = new MyContext();
    //do some stuff with this to identify something
    if(something)
    {
         //Do stuff
         ctx.MyObjects.Add(myObject);
         ctx.SaveChanges() //this is where my error was being thrown
    }
    else
    {
        //same stuff, just an update rather than add
    }
}

Я изменил его на следующее:

Parallel.ForEach(query, deet =>
{
    MyContext ctxCheck = new MyContext();
    //do some stuff with this to identify something
    if(something)
    {
         MyContext ctxAdd = new MyContext();
         //Do stuff
         ctxAdd .MyObjects.Add(myObject);
         ctxAdd .SaveChanges() //this is where my error was being thrown
    }
    else
    {
        MyContext ctxUpdate = new MyContext();
        //same stuff, just an update rather than add
        ctxUpdate.SaveChanges();
    }
}

Не уверен, что это "Лучшая практика", но она исправила мою проблему, если каждая параллельная операция использует свой собственный контекст.

Ответ 30

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

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

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

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

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