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.

Strongopinions
źródło
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.

fyjham
źródło
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

webtrifusion
źródło
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);
Ben
źródło
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.

Leniel Maccaferri
źródło
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

Wyłącznie
źródło
+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.
Pure.Krome
źródło
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.

innominate227
źródło
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; }
    }
}   
Wyczerpanie
źródło
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

Bilel Chaouadi
źródło
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.

jeszcze
źródło
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”.

Paulo
źródło
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

Arun Aravind
źródło
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.

Grzech
źródło
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
Zobacz także to pytanie: stackoverflow.com/questions/5820992/...
J. Polfer
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ę.

fightc2
źródło
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.

zardzewiały gwóźdź
źródło
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

Prakash
źródło
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; }
Tomo
źródło
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)

Moji
źródło
4

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

ajaysinghdav10d
źródło
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();
}
Ogglas
źródło
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

Tony
źródło
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();
                }
        }
    }
Prem Prakash
źródło
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
        }
Serj Sagan
źródło
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.

Mubarak
źródło
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);
}
Andrzej
źródło
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.

Ali
źródło
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.

rism
źródło
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).

J. Polfer
źródło
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.

Mahesh
źródło
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;
R. Salisbury
źródło
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