Entity Framework: "инструкция Store update, insert или delete повлияла на неожиданное количество строк (0)." [закрытый]



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




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




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



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

870   30  

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

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

  1. вы пытались обновить строку с одним или несколькими свойствамиConcurrency Mode: Fixed .. и оптимистичный параллелизм не позволил сохранить данные. То есть. некоторые из них изменили данные строки между моментом получения данных сервера и моментом сохранения данных сервера.
  2. вы попытались обновить или удалить строку, но строка не существует. Еще один пример того, как кто-то меняет данные (в данном случае удаляет) между ними получить затем сохранить или вы плоская наша попытка обновить поле, которое не является идентичностью (т. е. 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.

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

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

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

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

    Ничего не найдено.