Entity Framework: „Przechowywanie instrukcji aktualizacji, wstawiania lub usuwania wpłynęło na nieoczekiwaną liczbę wierszy (0)”. [Zamknięte]


324

Korzystam z Entity Framework do wypełnienia kontrolki siatki. Czasami po dokonaniu aktualizacji pojawia się następujący błąd:

Przechowywanie instrukcji aktualizacji, wstawiania lub usuwania wpłynęło na nieoczekiwaną liczbę wierszy (0). Elementy mogły zostać zmodyfikowane lub usunięte od czasu załadowania elementów. Odśwież wpisy ObjectStateManager.

Nie mogę wymyślić, jak to odtworzyć. Ale może to mieć coś wspólnego z tym, jak blisko siebie dokonuję aktualizacji. Czy ktoś to widział lub czy ktoś wie, do czego odnosi się komunikat o błędzie?

Edycja: Niestety nie mam już możliwości odtworzenia problemu, który tu miałem, ponieważ zrezygnowałem z tego projektu i nie pamiętam, czy w końcu znalazłem rozwiązanie, czy inny programista go naprawił, czy też obejrzałem go. Dlatego nie mogę przyjąć żadnych odpowiedzi.


Wystąpił ten błąd po wprowadzeniu zasady zabezpieczeń SQL Server na poziomie wiersza, która zezwala na aktualizacje wiersza do stanu, którego nie można odczytać (wyłączny predykat FILTER z dopuszczalnym predykatem BLOCK) . EntityFramework wymaga, aby zaktualizowany wiersz został odczytany po aktualizacji, w przeciwnym razie zakłada, że ​​był to błąd współbieżności (przynajmniej w przypadku korzystania z optymistycznej współbieżności).
xr280xr

Problemem może być niepoprawne określenie zakresu dla DBContext stackoverflow.com/questions/49154250/... (ten przykład dotyczy tożsamości ASPNET, ale dotyczy dowolnego kontekstu)
Simon_Weaver

Niezależnie od kontekstu tego błędu, dobrym pomysłem jest umieszczenie punktu przerwania w dowolnym miejscu, w którym kontekst jest tworzony. Czy spodziewałeś się, że zostanie on utworzony raz po załadowaniu strony internetowej, ale osiąga ten punkt przerwania 5 razy? Wtedy prawdopodobnie masz stan wyścigu. Spójrz, Request.Uriaby zobaczyć rzeczywisty adres URL żądania. W moim przypadku miałem trochę logiki śledzenia, która uderzała w moją stronę i niepotrzebnie ładowała kontekst z bazy danych (i od czasu do czasu ją aktualizowałem). Więc wtedy na rzeczywistej stronie, którą debugowałem, dane zostały zdeptane przez głupią logikę kodu śledzenia.
Simon_Weaver,

dodaj @ Html.AntiForgeryToken () w widoku
Vikas Sharma

Odpowiedzi:


199

Jest to efekt uboczny funkcji zwanej optymistyczną współbieżnością.

Nie jestem w 100% pewien, jak to włączyć / wyłączyć w Entity Framework, ale w gruncie rzeczy mówi to, że między momentem wyjęcia danych z bazy danych a zapisaniem zmian ktoś inny zmienił dane (co znaczyło, gdy odszedłeś aby go zapisać 0 wierszy zostało zaktualizowanych). W kategoriach SQL klauzula updatezapytania wherezawiera oryginalną wartość każdego pola w wierszu, a jeśli wpłynie na 0 wierszy, wie, że coś poszło nie tak.

Chodzi o to, że nie zastąpisz zmiany, o której nie wiedziała Twoja aplikacja - jest to po prostu mały środek bezpieczeństwa wprowadzony przez .NET we wszystkich twoich aktualizacjach.

Jeśli jest spójny, istnieje prawdopodobieństwo, że dzieje się to zgodnie z twoją logiką (np. Sam aktualizujesz dane inną metodą pomiędzy wyborem a aktualizacją), ale może to być po prostu warunek wyścigu między dwiema aplikacjami.


34
Dzieje się tak w środowisku jednego użytkownika (na mojej maszynie deweloperskiej), więc nie sądzę, że może to być wyścig. Wiążę niestandardową kontrolkę siatki za pomocą EntityDataSource, więc nie jestem pewien, co dokładnie dzieje się za kulisami, ale nie mam własnego kodu modyfikującego tabele. Czy istnieje sposób na zmianę tego ustawienia współbieżności?
strongopinions,

3
Myślę, że możesz w oparciu o kolumnę w modelu encji (znajduje się w oknie właściwości), ale chodzi o to, że po prostu zapobiegnie wyświetleniu błędu i nadal niczego nie zaktualizuje. Czy jesteś w stanie wyświetlić polecenia SQL idące do bazy danych (EG: SQL Server Profiler for MSSQL)? W ten sposób możesz zobaczyć, jaka aktualizacja została wygenerowana i powinieneś wiedzieć, dlaczego ta aktualizacja nie wpływa na żadne wiersze.
fyjham

9
Jeśli encja ma właściwość znacznika czasu, upewnij się, że masz ją zapisaną w swoim widoku i upewnij się, że jednostka poprawnie wypełnia znacznik czasu.
anIBMer

Miałem kolumnę ze znacznikiem czasu, a kiedy ją rozwiązałem, EF6.1 działał zgodnie z oczekiwaniami, dzięki za wskazówkę @anelBMer
JQII

3
Jeśli używasz znaczników czasu, obiekt, który chcesz usunąć, potrzebuje zestawu PK i właściwości RowVersion, aby pomyślnie go zaktualizować! Ustawiałem właściwość rowVersion (timestamp), po dołączeniu obiektu do odpowiedniego DbSet, dlatego nie działało. Dobra robota!
Legendy,

394

Natknąłem się na to i było to spowodowane tym, że pole identyfikatora (klucza) bytu nie było ustawione. Dlatego gdy kontekst poszedł do zapisania danych, nie mógł znaleźć identyfikatora = 0. Pamiętaj, aby umieścić punkt przerwania w instrukcji aktualizacji i sprawdź, czy identyfikator jednostki został ustawiony.

Z komentarza Paula Bellory

Miałem dokładnie ten problem, spowodowany zapomnieniem o włączeniu ukrytego identyfikatora wejściowego na stronie edycji .cshtml


3
+1 Miałem ten sam problem, co pomogło mi znaleźć rozwiązanie. Okazuje się, że miałem [Bind (Exclude = „OrderID”)] w moim modelu zamówienia, co powodowało, że wartość identyfikatora podmiotu wynosiła zero na HttpPost.
Dhaust

2
Właśnie tego mi brakowało. ID mojego obiektu to 0.
Azhar Khorasany

4
@ Html.HiddenFor (model => model.productID) - działał idealnie. Brakowało mi ID produktu na STRONIE EDYCJI (MVC RAZOR)
Ravi Ram

2
Miałem podobny problem, ale z pewnym zdziwieniem. Dla mnie problemem było to, że nie miałem poprawnie skonfigurowanej tabeli sql. Moje pole klucza podstawowego nie zostało ustawione na automatyczne zwiększenie. Więc EF wyśle ​​rekord, który próbowałem wstawić bez klucza, co jest w porządku, jeśli pamiętasz, aby powiedzieć sqlowi, że to pole jest automatycznym przyrostem, pole Tożsamości, o którym zapomniałem: <
Agile Noob

1
Ten sam problem, ale przy użyciu klucza złożonego. Jedna z kluczowych wartości nie została ustawiona.
obaylis

113

Wow, wiele odpowiedzi, ale dostałem ten błąd, kiedy zrobiłem coś nieco innego, o czym nikt inny nie wspomniał.

Krótko mówiąc, jeśli utworzysz nowy obiekt i powiesz EF, że został zmodyfikowany za pomocą, EntityState.Modifiedto wyrzuci ten błąd, ponieważ nie istnieje jeszcze w bazie danych. Oto mój kod:

MyObject foo = new MyObject()
{
    someAttribute = someValue
};

context.Entry(foo).State = EntityState.Modified;
context.SaveChanges();

Tak, to wydaje się głupie, ale pojawiło się, ponieważ omawiana metoda wcześniej foodo niego została stworzona wcześniej, teraz tylko someValueprzeszła i stworzyła foosię.

Łatwo naprawić, tylko zmiana EntityState.Modifiedna EntityState.Addedlub zmiana że cała linia do:

context.MyObject.Add(foo);

Dzięki za opublikowanie tego. To też był mój problem. Skopiowałem kod, który ustawiał stan na EntityState.Modified.
clayRay

23

Napotkałem ten sam błąd straszenia ... :) Wtedy zdałem sobie sprawę, że zapomniałem ustawić

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

dla klucza podstawowego aktualizowanego obiektu! Często zapominam o tej prostej, ale bardzo ważnej rzeczy!

Nawiasem mówiąc: HiddenForjest dla ASP.NET MVC.


3
Wydaje się, że to luka w zabezpieczeniach polegająca na przechowywaniu UserIdformularza, bardzo podatnego na ataki hakerów ... po tym należy wypełnićHttpContext.Current.User.Identity.Name
Serj Sagan

@SerjSagan masz rację ... ale dopóki wykonasz kilka kontroli po stronie serwera, aby potwierdzić UserId i bieżącą nazwę użytkownika, możesz iść.
Leniel Maccaferri

1
Chodzi mi o to, dlaczego nawet zapamiętaj, że i HiddenFortak będziesz musiał go pobrać HttpContext... W ogóle nie umieściłbym tej właściwości w formie, co zmusiłoby mnie do zawsze wypełniania jej po stronie serwera ...
Serj Sagan

16

Sprawdź, czy zapomniałeś atrybutu „DataKeyNames” w GridView. jest to konieczne podczas modyfikowania danych w GridView

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


+1. Idealne i proste rozwiązanie dla mnie. Wiążę GridView z EntityDataSource i nie ustawiłem tego na klucz podstawowy na obiekcie.
Andez

Wiemy, że interfejs Kendo nie obsługuje klucza złożonego, ale jeśli dodam nową kolumnę, która łączy moje klucze z jednym, co się wtedy dzieje?
Branislav

15

Problem jest spowodowany jedną z dwóch rzeczy: -

  1. Próbowano zaktualizować wiersz z jedną lub kilkoma właściwościami Concurrency Mode: Fixed.., a optymistyczna współbieżność uniemożliwiła zapisanie danych. To znaczy. niektóre zmieniły dane wiersza między czasem otrzymania danych serwera a momentem zapisania danych serwera.
  2. Próbowałeś zaktualizować lub usunąć wiersz, ale wiersz nie istnieje. Innym przykładem osoby zmieniającej dane (w tym przypadku usuwającej) pomiędzy pobieraniem, a następnie zapisywaniem LUB nie możesz, próbując zaktualizować pole, które nie jest Tożsamością (tj. StoreGeneratedPattern = Computed) I ten wiersz nie istnieje.

1
Może to być również spowodowane tym, że wszystkie właściwości obiektu, do których zostały przypisane, miały te same wartości, co wcześniej.
Serj Sagan

+1 dla drugiego. Miałem StoreGeneratedPattern = Brak, zmiana na StoreGeneratedPattern = Tożsamość rozwiązała problem. Dzięki
tkt986

12

Wystąpił ten sam błąd, ponieważ część PK była kolumną daty i godziny, a wstawiany rekord używał DateTime.Now jako wartości dla tej kolumny. Struktura encji wstawiałaby wartość z dokładnością do milisekund, a następnie szukała wartości, którą właśnie wstawiła, również z dokładnością do milisekund. Jednak SqlServer zaokrąglił tę wartość do drugiej precyzji, a zatem środowisko encji nie było w stanie znaleźć wartości precyzji milisekundowej.

Rozwiązaniem było obcięcie milisekund z DateTime.Now przed wstawieniem.


2
Mieliśmy ten sam problem, tyle że DateDateTime
wstawialiśmy

1
To samo tutaj. Mieliśmy rekord hurtowni danych i używaliśmy znacznika czasu jako części klucza. Znacznik czasu w hurtowni danych to SQL DateTime, ale znacznik czasu w C # nie jest zgodny. Zmieniłem typ danych SQL na DateTime2 (7), zaktualizowałem model EF i wszystko zostało naprawione.
mmcfly

Zmiana kolumny na Datetime2 (7) również działała dla mnie. Dzięki @mmcfly
Dzejms

10

Miałem ten sam problem i @ webtrifusion za odpowiedź pomogła znaleźć rozwiązanie.

Mój model używał Bind(Exclude)atrybutu na identyfikatorze jednostki, co powodowało, że wartość identyfikatora jednostki była zerowa na 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; }
    }
}   

Podobny problem, ze względów bezpieczeństwa, mam Bind (include = niektóre pola). Identyfikatora nie było na liście. Dodałem również jako ukryte wejście. Musiał skasować coś wygenerowanego przez MVC lub w ogóle nie było tam identyfikatora. Dzięki za pomoc.
MusicAndCode

10

Miałem ten sam problem, zorientowałem się, że był spowodowany RowVersion, który był zerowy. Sprawdź, czy identyfikator i RowVersion nie mają wartości zerowej .

Aby uzyskać więcej informacji, zapoznaj się z tym samouczkiem

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


wersja wiersza była w moim przypadku zerowa
Prakash

W moim przypadku przypadkowo usunąłem pole Id w moim [Bind (Include = properties)]. Dodaj to z powrotem i działało dobrze.
Caverman,

8

Zacząłem otrzymywać ten błąd po zmianie z pierwszego modelu na pierwszy. Mam wiele wątków aktualizujących bazę danych, z których niektóre mogą aktualizować ten sam wiersz. Nie wiem, dlaczego nie miałem problemu z pierwszym użyciem modelu, zakładam, że używa innej domyślnej współbieżności.

Aby obsłużyć go w jednym miejscu, znając warunki, w których może wystąpić, dodałem następujące przeciążenie do mojej klasy 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();
            }
        }
}

Następnie nazywane, SaveChanges(true)gdziekolwiek dotyczy.


1
OK, wszyscy inni narzekają na problem, pokazując, jak mogą go uruchomić itp., Ale ta odpowiedź ma fajną odpowiedź. Używam modelu kontynuacji aktualizacji (tutaj nie ma przycisku Zapisz, kochanie) i otrzymywałem to na aktualizacjach siatki, gdy wątek EF pozostawał w tyle, i rozwiązałem go. Genialna robota, moje dobre imię ... sprawiłeś, że wyglądam jak bohater - stojąc na ramieniu gigantów !!
Tony Trembath-Drake

Pomógł mi również, spójrz na to, aby uzyskać więcej opcji
Zvi Redler

7

Musisz jawnie dołączyć BoundField klucza podstawowego. Jeśli nie chcesz, aby użytkownik widział klucz podstawowy, musisz go ukryć za pomocą css:

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

Gdzie „ukryty” to klasa w css, która ma ustawioną opcję wyświetlania na „none”.


1
hah, poszukałeś mnie w tym, że usunąłem moje ukryte pole identyfikatora w ASP.NET MVC. Dzięki @Paulo! :)
Tomasz Iniewicz

7

Podczas edycji dołącz identyfikator lub klucz podstawowy encji jako ukryte pole w widoku

to znaczy

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

to rozwiązuje problem.

Również jeśli twój model zawiera nieużywany przedmiot, to również to i wyślij to do kontrolera


7

Natknąłem się również na ten błąd. Okazało się, że problem został spowodowany przez wyzwalacz na stole, na który próbowałem zapisać. Trigger użył „ZAMIAST WSTAWIENIA”, co oznacza, że ​​do tej tabeli kiedykolwiek wstawiono 0 wierszy, stąd błąd. Na szczęście może się zdarzyć, że funkcja wyzwalacza była niepoprawna, ale myślę, że może to być poprawna operacja, którą należy jakoś obsłużyć w kodzie. Mam nadzieję, że to komuś pomoże.


2
Podmiot można oszukać, że wiersze zostały dodane, zwracając instrukcję SELECT (z kolumną klucza podstawowego) z wyzwalacza.
jahu

1
Aby rozwinąć komentarz @jahu, musiałem uzyskać rzeczywisty identyfikator nowo wstawionego elementu, który ma zostać zwrócony z mojego wyzwalacza, a nazwa kolumny musi pasować do kolumny tożsamości tabeli wyzwalaczy (w moim przypadku właściwie widok, więc nie nie ma własnej tożsamości, ale oszukałem edmx, aby uwierzył, że tak jest). Mój wyzwalacz wstawiał wstawkę do osobnej tabeli, więc właśnie dodałem ten ostatni wiersz do mojego wyzwalacza:SELECT SCOPE_IDENTITY() as MyViewId
DannyMeister


W moim przypadku przeprowadzałem operację usuwania na obiektach w kolekcji podrzędnej, ale wystąpił wyzwalacz przy usuwaniu dla jednej z jednostek podrzędnych, który spowodował usunięcie innej z jednostek podrzędnych. Spowodowało to błąd, ponieważ wpłynęło to na N-1 wierszy z powodu usunięcia przez wyzwalacz jednej z encji potomnych, zanim struktura encji spróbowała je usunąć.
skeletank,

6

Natrafiłem na ten problem w tabeli, w której brakowało klucza podstawowego i miał kolumnę DATETIME (2, 3) (więc „klucz podstawowy” encji był kombinacją wszystkich kolumn) ... Podczas wykonywania wstawiania znacznik czasu miał bardziej precyzyjny czas (2018-03-20 08: 29: 51.8319154), który został skrócony do (2018-03-20 08: 29: 51.832), więc wyszukiwanie kluczowych pól nie powiedzie się.


5

Też miałem ten błąd. Istnieją sytuacje, w których jednostka może nie być świadoma faktycznego kontekstu bazy danych, którego używasz, lub model może być inny. W tym celu ustaw: EntityState.Modified; do EntityState.Added;

Aby to zrobić:

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

Zapewni to, że jednostka wie, że używasz lub dodajesz stan, z którym pracujesz. W tym momencie należy ustawić wszystkie prawidłowe wartości modelu. Uważaj, aby nie stracić żadnych zmian, które mogły zostać wprowadzone w tle.

Mam nadzieję że to pomoże.


1
jesteś gurú! to działa dla mnie!
Hernaldo Gonzalez,

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

Moja wersja wiersza była zerowa, więc musiałem dodać to do widoku, który rozwiązał mój problem


Nie przekazałem RowVersion z widoku do akcji edycji, a ponadto zapomniałem zrobić wiązania modelu dla RowVersion. Podczas zapisywania obiektu do db potrzebujesz poprzedniej wartości RowVersion przesłanej do db wraz z obiektem do sprawdzenia współbieżności. Robisz głupie błędy, gdy potrzebujesz rzeczy szybciej!
Dhanuka777,

5

Linia [DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.None)]zrobiła lewę w moim przypadku:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;


[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int? SomeNumber { get; set; }

4

Upewnij się tylko, że tabela i formularz mają zaktualizowany klucz podstawowy i edmx.

odkryłem, że wszelkie błędy podczas aktualizacji były zwykle spowodowane: - Brak klucza podstawowego w tabeli - Brak klucza podstawowego w widoku / formularzu edycji (np. @Html.HiddenFor(m=>m.Id)


4

Miałem ten sam problem. W moim przypadku próbowałem zaktualizować klucz podstawowy, co jest niedozwolone.


4

Ten błąd pojawia się sporadycznie podczas korzystania z async metody. Nie stało się tak odkąd przełączyłem się na metodę synchroniczną.

Błędy sporadycznie:

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

Działa cały czas:

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

Chociaż rozwiązało to mój problem, służyło to wskazaniu na podstawowy problem wspomniany wcześniej w tym poście na temat wersji PK i Row. Zaniedbałem dodanie mapy schematów dla nowej tabeli, co dodatkowo skomplikowało to, że PK nie przestrzegał zasady konwencji nazewnictwa. <Nazwa tabeli> ID.
midohioboarder

3

Wystąpił ten błąd, gdy usuwałem niektóre wiersze w bazie danych (w pętli) i dodawałem nowe w tej samej tabeli.

Rozwiązaniem było dla mnie dynamiczne tworzenie nowego kontekstu w każdej iteracji pętli


Musiałem zrobić to samo, wciąż nie jestem pewien, dlaczego problem pojawił się w pierwszej kolejności, ale to działa.
Jed Grant,

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

Czy możesz wyjaśnić, do czego odnosi się to „to” i co to jest ObjectStateManager? Próbuję tego w naszej podstawowej klasie repozytorium, ale dostaję błędy
Naomi

3

Dzieje się tak również wtedy, gdy próbujesz wprowadzić unikalną sytuację z ograniczeniami, tj. Jeśli możesz mieć tylko jeden typ adresu na pracodawcę i próbujesz wstawić drugą tego samego typu u tego samego pracodawcy, otrzymasz ten sam problem .

LUB

Może się to również zdarzyć, jeśli wszystkie właściwości obiektu, do których zostały przypisane, zostały przypisane z takimi samymi wartościami, jak wcześniej.

        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

Jeśli próbujesz utworzyć mapowanie w pliku edmx na „funkcję Imports”, może to spowodować ten błąd. Po prostu wyczyść pola wstawiania, aktualizacji i usuwania, które znajdują się w Szczegółach mapowania dla danej encji w edmx, i powinno działać. Mam nadzieję, że to wyjaśniłem.


2

Ten wyjątek wystąpił podczas dołączania obiektu, który nie istniał w bazie danych. Zakładałem, że obiekt został załadowany z osobnego kontekstu, ale jeśli użytkownik odwiedził witrynę po raz pierwszy, obiekt został stworzony od podstaw. Mamy automatycznie zwiększające się klucze podstawowe, więc mógłbym je wymienić

context.Users.Attach(orderer);

z

if (orderer.Id > 0) {
    context.Users.Attach(orderer);
}

2

Mam ten sam problem. Ale było to spowodowane moim błędem. Właściwie zapisywałem obiekt zamiast go dodawać. To był konflikt.


2

Jednym ze sposobów debugowania tego problemu w środowisku Sql Server jest użycie Sql Profiler dołączonego do twojej kopii SqlServer, lub jeśli używasz wersji Express, pobierz kopię Express Profiler za darmo z CodePlex, klikając poniższy link:

Express Profiler

Za pomocą Sql Profiler możesz uzyskać dostęp do wszystkiego, co jest wysyłane przez EF do bazy danych. W moim przypadku było to:

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

Skopiowałem wkleiłem to do okna zapytania w Sql Server i wykonałem. Rzeczywiście, chociaż uruchomiono, to zapytanie wpłynęło na 0 rekordów, dlatego błąd został zwrócony przez EF.

W moim przypadku problem został spowodowany przez CategoryID.

Identyfikator EF nie został zidentyfikowany przez identyfikator EF wysłany do bazy danych, dlatego dotyczy 0 rekordów.

Nie była to jednak wina EF, ale raczej buggy null łączący „??” instrukcja w widoku kontrolera, który wysyłał bzdury do warstwy danych.


2

Żadna z powyższych odpowiedzi nie obejmowała mojej sytuacji ani jej rozwiązania.

Kod, w którym błąd został zgłoszony w kontrolerze MVC5:

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

Otrzymałem ten wyjątek, gdy zapisywałem obiekt poza widokiem edycji. Powodem tego było to, że kiedy wróciłem, aby go zapisać, zmodyfikowałem właściwości, które utworzyły klucz główny na obiekcie. Zatem ustawienie jego stanu na Zmodyfikowany nie miało sensu dla EF - był to nowy wpis, a nie zapisany wcześniej.

Możesz rozwiązać ten problem, albo A) modyfikując wywołanie zapisu, aby dodać obiekt, lub B) po prostu nie zmieniaj klucza podstawowego podczas edycji. Zrobiłem B).


2

Kiedy zaakceptowana odpowiedź brzmiała: „ nie spowoduje to zastąpienia zmiany, o której nie wiedziała Twoja aplikacja ”, byłem sceptyczny, ponieważ mój obiekt został nowo utworzony. Ale potem okazuje się, że byłoINSTEAD OF UPDATE, INSERT- TRIGGER do tabeli dołączono załącznik, który aktualizował kolumnę obliczeniową tej samej tabeli.

Gdy zmienię to na AFTER INSERT, UPDATE, działało dobrze.


2

Zdarzyło mi się to z powodu niedopasowania między datetime a datetime2. O dziwo zadziałało dobrze, zanim tester odkrył problem. Model My Code First obejmował DateTime jako część klucza podstawowego:

[Key, Column(Order = 2)]  
public DateTime PurchasedDate { get; set; } = (DateTime)SqlDateTime.MinValue;

Wygenerowana kolumna jest kolumną daty i godziny. Podczas wywoływania SaveChanges EF wygenerował następujący kod SQL:

-- Region Parameters
DECLARE @0 Int = 2
DECLARE @1 Int = 25
DECLARE @2 Int = 141051
DECLARE @3 DateTime2 = '2017-07-27 15:16:09.2630000' --(will not equal a datetime value)
-- EndRegion
UPDATE [dbo].[OrganizationSurvey]
SET [OrganizationSurveyStatusId] = @0
WHERE ((([SurveyID] = @1) AND ([OrganizationID] = @2)) AND ([PurchasedDate] = @3))

Ponieważ próbował dopasować kolumnę datetime do wartości datetime2, nie zwrócił żadnych wyników. Jedyne rozwiązanie, o jakim mogłem pomyśleć, to zmienić kolumnę na datetime2:

[Key, Column(Order = 2, TypeName = "DateTime2")]  
public DateTime PurchasedDate { get; set; } = (DateTime)SqlDateTime.MinValue;

1
Dziwność tego, że działa kontra nie działa, ma związek z podstawowym formatem / bazą datetimekontra datetime2. Zasadniczo niektóre wartości milisekund będą pasować do siebie, inne nie. To samo przydarzyło mi się i również się zmieniłem DateTime2.
xr280xr

+1 Żałuję, że nie mogę dla ciebie dać +100. Po przejrzeniu wielu miejsc w końcu to znalazłem i zdałem sobie sprawę, że rzeczywiście miałem Datetime jako część mojego klucza podstawowego. Tak, to naprawiło to. Zaktualizowałem kolumnę do Datetime2 i zadziałało. Teraz moja wołowina jest w Entity Framework za opracowanie tak głupiego zapytania, które zmusza mnie do tego.
Catchops
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.