Nie można zaktualizować obiektu EntitySet - ponieważ ma on DefiningQuery i nie istnieje element <UpdateFunction>

533

Korzystam z Entity Framework 1 z .net 3.5.

Robię coś takiego prostego:

var roomDetails = context.Rooms.ToList();

foreach (var room in roomDetails)
{        
   room.LastUpdated = DateTime.Now;
}

Otrzymuję ten błąd, gdy próbuję:

 context.SaveChanges();

Dostaję błąd:

Nie można zaktualizować EntitySet - ponieważ ma on DefiningQuery i nie istnieje element <UpdateFunction> w elemencie <ModificationFunctionMapping> w celu obsługi bieżącej operacji.

Robię wiele aktualizacji w kontekście i nie mam żadnych problemów, tylko wtedy, gdy próbuję zaktualizować ten konkretny byt.

Całe moje wyszukiwanie pokazuje to samo, że nie ma zadeklarowanego klucza podstawowego w encji, którą próbuję zaktualizować. Ale niestety mam zadeklarowany klucz podstawowy ...

iKode
źródło
61
Popełniłem błąd, nie było na stole klucza podstawowego, dziękuję za poświęcony czas! Przepraszam za niedogodności!
iKode,
1
Akurat mnie - prawdopodobnie stworzony 1000 tabele z kluczy podstawowych i zapomniałem jeden - komunikat wyjątek nie pomaga
Peter Munnings
1
świetny. naprawdę zapomniałem dodać klucz podstawowy do tabeli. Starajmy się uważać)
AEMLoviji

Odpowiedzi:

1022

Zwykle dzieje się tak, ponieważ jeden z następujących powodów:

  • Zestaw jednostek jest odwzorowany z widoku bazy danych
  • Niestandardowe zapytanie do bazy danych
  • Tabela bazy danych nie ma klucza podstawowego

Po wykonaniu tej czynności może być konieczne zaktualizowanie w projektancie Entity Framework (lub alternatywnie usunięcie encji, a następnie dodanie jej), zanim przestanie się pojawiać błąd.

Ladislav Mrnka
źródło
2
Pamiętaj, aby również zmienić sklep: Schemat na tylko Schemat dla tego zestawu EntitySet, jeśli nadal masz problemy.
Geoff,
53
Następnie usuń i ponownie utwórz encję, ponieważ aktualizacja nie działa poprawnie w projektancie EF.
Suncat2000
48
PK było odpowiedzią. Dzięki!
nrod
1
Aktualizacja w projektancie EF działała dla mnie dobrze po dodaniu klucza podstawowego do bazy danych. Korzystanie z EF 5.0 i .net 4.0
StillLearnin
1
To samo tutaj! Dzięki ... musiałem usunąć tabelę i ponownie dodać do EF, aby ją wziąć
ajzeffer
90

Wystarczy dodać klucz podstawowy do tabeli. Otóż ​​to. Problem rozwiązany.

ALTER TABLE <TABLE_NAME>
ADD CONSTRAINT <CONSTRAINT_NAME> PRIMARY KEY(<COLUMN_NAME>)
Jebastin J
źródło
13
i nie zapomnij kliknąć „Aktualizuj model z bazy danych” w pliku .edmx
Bashar Abu Shamaa,
@BasharAbuShamaa ta odpowiedź nie jest ważna bez tych szczegółów.
Kehlan Krumme
66

Tak jest w moim przypadku. Samo usunięcie spowodowało kolejny błąd. Postępowałem zgodnie z krokami tego postu oprócz ostatniego. Dla Twojej wygody skopiowałem 4 kroki z posta, które śledziłem, aby rozwiązać problem w następujący sposób:

  1. Kliknij prawym przyciskiem myszy plik edmx, wybierz Otwórz za pomocą, edytor XML
  2. Znajdź encję w elemencie edmx: StorageModels
  3. Usuń całkowicie DefiningQuery
  4. Zmień nazwę store:Schema="dbo", aby Schema="dbo"(w przeciwnym razie kod wygeneruje błąd mówiąc, że nazwa jest niepoprawna)
kavitha Reddy
źródło
Dziękuję bardzo - to właśnie naprawiło mój problem. Całkiem niepokojące, że nie zostało to naprawione w EF. I całkiem niesamowite, że to rozgryzłeś!
Rower Dave
Próbowałem usunąć obiekt i dodać go ponownie. Ponowna kompilacja. Czyszczenie. Nic nie działało dla mnie poza tym.
vintastic
1
To rozwiązało mój problem, ale nie wiem, jak wymyśliłeś odpowiedzi i dlaczego Twoja sugestia rozwiązała problem.
swcraft
Co się stanie, jeśli musisz zaktualizować model bazy danych? Zrobiłem „Uaktualnij model z bazy danych”, dzięki czemu mój model był całkowicie bezużyteczny. Musiałem cofnąć i zacząć od nowa. Jeśli jest na to jakiś sposób?
Gary
To naprawdę dziwny problem. Czy są jakieś informacje na temat tego, jak ten problem występuje, aby go uniknąć? Niemniej jednak - pomogło
r3dst0rm
41

Pamiętaj, że być może twoja jednostka ma klucz podstawowy, ale twoja tabela w bazie danych nie ma klucza podstawowego .

Majid
źródło
1
Jak pokonać, jeśli nie możemy zmienić tabeli bazy danych?
Kai Hartmann
Jeśli możesz zmienić tabelę DB na klucz podstawowy, wówczas generator kodu przestanie popełniać te same błędy, usunięcie klucza z EF spowoduje wiele innych problemów.
Chris Schaller
30

AKTUALIZACJA: Ostatnio otrzymałem kilka pozytywnych opinii na ten temat, więc pomyślałem, że dam znać ludziom, że poniższe porady nie są najlepsze. Odkąd zacząłem się zastanawiać, wykonując Entity Framework na starych bazach danych bezkluczykowych, zdałem sobie sprawę, że najlepszą rzeczą, jaką możesz zrobić BY FAR, jest zrobienie tego przez odwrócenie kodu. Istnieje kilka dobrych artykułów na ten temat. Postępuj zgodnie z nimi, a następnie, jeśli chcesz dodać klucz, użyj adnotacji danych, aby „sfałszować” klucz.

Załóżmy na przykład, że wiem, że mój stół Orders, chociaż nie ma klucza podstawowego, gwarantuje, że będzie miał tylko jeden numer zamówienia na klienta. Ponieważ są to dwie pierwsze kolumny w tabeli, ustawiłem pierwsze klasy kodu, aby wyglądały następująco:

    [Key, Column(Order = 0)]
    public Int32? OrderNumber { get; set; }

    [Key, Column(Order = 1)]
    public String Customer { get; set; }

Robiąc to, w zasadzie sfałszujesz EF, aby uwierzyć, że istnieje klastrowany klucz złożony z OrderNumber i Customer. Umożliwi to wykonywanie wstawek, aktualizacji itp. W tabeli bezkluczykowej.

Jeśli nie jesteś zbyt zaznajomiony z robieniem kodu w pierwszej kolejności, znajdź dobry samouczek na temat Entity Framework Code First. Następnie znajdź jeden w Odwróć kod pierwszy (który robi kod pierwszy z istniejącą bazą danych). Więc po prostu wróć tutaj i ponownie spójrz na moją kluczową radę. :)

Oryginalna odpowiedź :

Po pierwsze: jak powiedzieli inni, najlepszą opcją jest dodanie klucza podstawowego do tabeli. Kropka. Jeśli możesz to zrobić, nie czytaj dalej.

Ale jeśli nie możesz lub po prostu nienawidzisz siebie, istnieje sposób, aby to zrobić bez klucza podstawowego.

W moim przypadku pracowałem ze starszym systemem (pierwotnie płaskie pliki na AS400 przeniesione do Access, a następnie przeniesione do T-SQL). Musiałem więc znaleźć sposób. To jest moje rozwiązanie. Poniższe działało dla mnie przy użyciu Entity Framework 6.0 (najnowsza wersja NuGet w chwili pisania tego tekstu).

  1. Kliknij prawym przyciskiem myszy plik .edmx w Eksploratorze rozwiązań. Wybierz „Otwórz za pomocą ...”, a następnie wybierz „Edytor XML (tekst)”. Będziemy tutaj ręcznie edytować automatycznie wygenerowany kod.

  2. Poszukaj takiej linii:
    <EntitySet Name="table_name" EntityType="MyModel.Store.table_name" store:Type="Tables" store:Schema="dbo" store:Name="table_nane">

  3. Usuń store:Name="table_name"z końca.

  4. Zmień store:Schema="whatever"naSchema="whatever"

  5. Spójrz poniżej tego wiersza i znajdź <DefiningQuery>tag. Będzie miał w nim dużą, starą instrukcję. Usuń tag i jego zawartość.

  6. Teraz twoja linia powinna wyglądać mniej więcej tak:
    <EntitySet Name="table_name" EntityType="MyModel.Store.table_name" store:Type="Tables" Schema="dbo" />

  7. Mamy coś jeszcze do zmiany. Przejrzyj plik i znajdź to:
    <EntityType Name="table_name">

  8. W pobliżu prawdopodobnie zobaczysz komentarz z ostrzeżeniem, że nie zidentyfikowano klucza podstawowego, więc klucz został wyprowadzony, a definicja jest tabelą / widokiem tylko do odczytu. Możesz go zostawić lub usunąć. Usunąłem to.

  9. Poniżej znajduje się <Key>tag. Tego właśnie używa Entity Framework do wstawiania / aktualizacji / usuwania. UPEWNIJ SIĘ, ŻE ROBISZ PRAWO. Właściwość (lub właściwości) w tym znaczniku muszą wskazywać jednoznacznie identyfikowalny wiersz. Załóżmy na przykład, że wiem, że mój stół orders, chociaż nie ma klucza podstawowego, gwarantuje, że będzie miał tylko jeden numer zamówienia na klienta.

Mój wygląda więc tak:

<EntityType Name="table_name">
              <Key>
                <PropertyRef Name="order_numbers" />
                <PropertyRef Name="customer_name" />
              </Key>

Poważnie, nie róbcie tego źle. Powiedzmy, że chociaż nigdy nie powinno być duplikatów, jakoś dwa wiersze dostają się do mojego systemu z tym samym numerem zamówienia i nazwą klienta. Whooops! To właśnie dostaję za nieużywanie klucza! Więc używam Entity Framework, aby go usunąć. Ponieważ wiem, że duplikat jest jedynym zamówieniem złożonym dzisiaj, robię to:

var duplicateOrder = myModel.orders.First(x => x.order_date == DateTime.Today);
myModel.orders.Remove(duplicateOrder);

Zgadnij co? Właśnie usunąłem zarówno duplikat, jak i oryginał! Dzieje się tak, ponieważ powiedziałem Entity Framework, że numer_kolejny / nazwa_komeru to mój klucz podstawowy. Więc kiedy powiedziałem mu, aby usunąć duplikat zamówienia, to w tle było coś takiego:

DELETE FROM orders
WHERE order_number = (duplicateOrder's order number)
AND customer_name = (duplicateOrder's customer name)

I z tym ostrzeżeniem ... powinieneś już iść!

Pharylon
źródło
Znalazłem tę odpowiedź po znalezieniu tego samego rozwiązania problemu. Zdecydowanie poprawna odpowiedź! Tylko zdefiniowanie klucza podstawowego, jak wspomniano w innych odpowiedziach, nie pomoże w wielu przypadkach.
Obl Tobl,
19

Może się to również zdarzyć, jeśli model danych jest nieaktualny.

Mam nadzieję, że uratuje to frustrację kogoś innego :)

mob1lejunkie
źródło
6

Otrzymywałem ten sam komunikat o błędzie, ale w moim scenariuszu próbowałem zaktualizować jednostki wyprowadzone z relacji wiele do wielu przy użyciu PJT (Pure Join Table).

Po przeczytaniu innych postów pomyślałem, że mogę to naprawić, dodając dodatkowe pole PK do tabeli łączenia ... Jednak jeśli dodasz kolumnę PK do tabeli łączenia, nie będzie to już PJT i stracisz wszystkie zalety struktury encji, takie jak automatyczne mapowanie relacji między jednostkami.

Tak więc rozwiązaniem w moim przypadku była zmiana tabeli łączenia na DB, aby utworzyć PK, który zawiera OBIE kolumny z zagranicznym identyfikatorem.

Kerry Randolph
źródło
Czy tak zawsze działało generowanie EDMX? Jestem przyzwyczajony do pracy z Code First, który nie wymaga PK na czystej tabeli łączenia.
Michael Hornfeck
4

może wystąpić błąd, jeśli tabela nie ma klucza podstawowego, w tym przypadku jest ona „tylko do odczytu”, a komenda db.SaveChanges () zawsze spowoduje błąd

Ruben.sar
źródło
4

Ustaw klucz główny, a następnie zapisz tabelę i odśwież, a następnie przejdź do Model.edmx usuń tabelę i uzyskaj ponownie.

Ali Raza
źródło
3

więc to prawda, po prostu dodaj klucz podstawowy

Uwaga: upewnij się, że podczas aktualizacji diagramu EF z bazy danych wskazujesz na właściwą bazę danych, w moim przypadku ciąg połączenia wskazywał na lokalną bazę danych zamiast aktualnej bazy danych deweloperów, uczeń błąd wiem, ale chciałem to opublikować, ponieważ może być bardzo frustrujące, jeśli jesteś przekonany, że dodałeś klucz podstawowy i nadal pojawia się ten sam błąd

Spyder
źródło
2

Miałem ten sam problem. Jak powiedział ten wątek: Moja tabela nie miała PK, więc ustawiłem PK i uruchomiłem kod. Niestety błąd pojawił się ponownie. Następnie usunąłem połączenie DB (usuń plik .edmx w folderze Model Eksploratora rozwiązań) i ponownie je utworzyłem. Błąd zniknął po tym. Dziękujemy wszystkim za podzielenie się swoimi doświadczeniami. Oszczędza dużo czasu.

Namal
źródło
1

Dostawałem ten problem, ponieważ generowałem mój EDMX z istniejącej bazy danych (zaprojektowanej przez kogoś innego i używam tutaj terminu „zaprojektowany” luźno).

Okazało się, że stół nie miał żadnych kluczy. EF generował model z wieloma wieloma kluczami. Musiałem dodać klucz podstawowy do tabeli db w SQL, a następnie zaktualizować mój model w VS.

To naprawiło to dla mnie.

Sztywny
źródło
1

To nie jest nowa odpowiedź, ale pomoże komuś, kto nie jest pewien, jak ustawić klucz podstawowy dla swojej tabeli. Użyj tego w nowym zapytaniu i uruchom. Spowoduje to ustawienie kolumny UniqueID jako klucza podstawowego.

USE [YourDatabaseName]
GO

Alter table  [dbo].[YourTableNname]
Add Constraint PK_YourTableName_UniqueID Primary Key Clustered (UniqueID);
GO
JessS
źródło
1

wprowadź opis zdjęcia tutaj

W moim przypadku zapomniałem zdefiniować Podstawowy klucz do tabeli. Więc przypisz jak pokazano na obrazku i odśwież tabelę z „Aktualizuj model z bazy danych” z pliku .edmx. Mam nadzieję, że to pomoże !!!

Yogesh Dangre
źródło
0

Dodanie klucza podstawowego również mi działało!

Gdy to zrobisz, oto jak zaktualizować model danych bez usuwania go -

Kliknij prawym przyciskiem myszy stronę projektanta encji edmx i „Aktualizuj model z bazy danych”.

Abhishek Poojary
źródło
0

Miałem dokładnie ten sam problem, niestety dodanie klucza podstawowego nie rozwiązuje problemu. Oto jak rozwiązuję mój:

  1. Upewnij się, że masz primary keyna stole, więc zmienię swój stół i dodam klucz podstawowy.
  2. Delete the ADO.NET Entity Data Model (plik edmx), którego używam do mapowania i łączenia się z moją bazą danych.
  3. Add again a new file of ADO.NET Entity Data Model do połączenia z moją bazą danych i do mapowania właściwości mojego modelu.
  4. Clean and rebuild the solution.

Problem rozwiązany.

Willy David Jr
źródło
0

po prostu dodaj klucz podstawowy do swojego stołu, a następnie ponownie utwórz EF

Sulyman
źródło
0

Musiałem tylko usunąć tabelę z modelu i zaktualizować model ponownie, przywracając tabelę. Wydaje mi się, że klucz główny został utworzony po wciągnięciu tabeli do modelu.

dangalg
źródło
0

Pojawił się ten problem i uważam, że był on spowodowany, ponieważ usunąłem Indeks z klucza podstawowego moich tabel i zastąpiłem go indeksem niektórych innych pól w tabeli.

Po usunięciu indeksu klucza podstawowego i odświeżeniu edmx, wstawki przestały działać.

Odświeżyłem tabelę do starszej wersji, odświeżyłem edmx i wszystko działa ponownie.

Powinienem zauważyć, że kiedy otworzyłem EDMX w celu rozwiązania tego problemu, sprawdzając, czy zdefiniowano klucz podstawowy, tak było. Żadna z powyższych sugestii mi nie pomogła. Ale odświeżenie indeksu klucza podstawowego wydawało się działać.

armstb01
źródło
0

Otwórz plik .edmx w edytorze XML, a następnie usuń znacznik z tagu, a także zmień sklep: Schema = "dbo" na Schema = "dbo" i odbuduj rozwiązanie, teraz błąd zostanie rozwiązany i będziesz mógł zapisać dane.

Sharad Tiwari
źródło
0

Znalazłem oryginalną odpowiedź dotyczącą aktualizacji pliku .edmx najlepiej w mojej sytuacji. Po prostu nie byłem zbyt szczęśliwy z powodu zmiany modelu za każdym razem, gdy był aktualizowany z bazy danych. Dlatego napisałem dodatkowy plik szablonu tekstowego, który jest automatycznie wywoływany, gdy po zmianie modelu - podobnie jak encje są generowane ponownie. Zamieszczam to tutaj w tym komentarzu. Aby to działało, upewnij się, że nadasz mu nazwę {nazwa modelu} .something.tt i przechowujesz go w tym samym folderze co folder .edmx. Nazwałem to {nazwa modelu} .NonPkTables.tt. Sam nie generuje pliku z powodu niepoprawnej definicji rozszerzenia pliku w drugim wierszu. Zapraszam do korzystania.

<#@ template language="C#" debug="false" hostspecific="true"#>
<#@ output extension="/" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Data" #>
<#@ assembly name="System.Windows.Forms" #>
<#@ assembly name="System.Xml" #>
<#@ assembly name="System.Xml.Linq"#>
<#@ assembly name="%VS120COMNTOOLS%..\IDE\EntityFramework.dll" #>
<#@ assembly name="%VS120COMNTOOLS%..\IDE\Microsoft.Data.Entity.Design.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Windows.Forms" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="System.Xml.Linq" #>
<#@ import namespace="System.Globalization" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.Data.Entity.Core.Metadata.Edm" #>
<#@ import namespace="System.Data.Entity.Core.Mapping" #>
<#@ import namespace="System.CodeDom" #>
<#@ import namespace="System.CodeDom.Compiler" #>
<#@ import namespace="Microsoft.CSharp"#>
<#@ import namespace="System.Text"#>
<#@ import namespace="System.Diagnostics" #>

<#
    string modelFileName= this.Host.TemplateFile.Split('.')[0] + ".edmx";
    string edmxPath = this.Host.ResolvePath( modelFileName );

    // MessageBox.Show( this.Host.TemplateFile + " applied." );
    var modelDoc = XDocument.Load(edmxPath);
    var root = modelDoc.Root;
    XNamespace nsEdmx = @"http://schemas.microsoft.com/ado/2009/11/edmx";
    XNamespace ns = @"http://schemas.microsoft.com/ado/2009/11/edm/ssdl";

    var runtime = root.Elements(nsEdmx + "Runtime").First();
    var storageModels = runtime.Elements(nsEdmx + "StorageModels").First();
    XNamespace nsStore = @"http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator";

    var schema = storageModels.Elements(ns + "Schema").First();
    XNamespace nsCustomAnnotation = @"http://schemas.microsoft.com/ado/2013/11/edm/customannotation";

    var entityTypes = schema.Nodes().OfType<XComment>().Where(c => c.Value.Contains("warning 6002: The table/view"));
    bool changed = false;

    foreach (var node in entityTypes)
    {
        var element = node.ElementsAfterSelf().First();
        string entityName = element.Attribute("Name").Value;

        // Find EntitySet in EntityContainer.
        var entityContainer = schema.Elements(ns + "EntityContainer").First();
        var entitySet = entityContainer.Elements(ns + "EntitySet").First(s => s.Attribute("Name").Value == entityName);

        // Change "store:Schema" attribute to "Schema" attribute.
        var attribute = entitySet.Attribute(nsStore + "Schema");

        if (attribute != null)
        {
            string schemaName = entitySet.Attribute(nsStore + "Schema").Value;
            entitySet.Attribute(nsStore + "Schema").Remove();
            entitySet.Add(new XAttribute("Schema", schemaName));
            changed |= true;
        }

        // Remove the DefiningQuery element.
        var definingQuery = entitySet.Element(ns + "DefiningQuery");

        if (definingQuery != null)
        {
            definingQuery.Remove();
            changed |= true;        
            Debug.WriteLine(string.Format("Removed defining query of EntitySet {0}.", entityName));
        }
    }

    if (changed)
        modelDoc.Save(edmxPath);
#>
Arno Tolmeijer
źródło
-1

Napotkałem ten sam komunikat o błędzie, aby wstawić rekord do tabeli mającej relację wiele do wielu . Mój schemat bazy danych to:

Student (Id , Name)
Course (Code , Title),
Student-Course (Student_ID, Course_Code)

Tabela Student i zajęć mają klucze podstawowe identyfikator i kod odpowiednio , podczas gdy tabela Student Kurs ma dwa klucze obce odwzorowanych z tabelami Studenckich i kurs.

Logicznie schemat jest poprawny, ale popełniłem błąd w bazie danych, ponieważ każda tabela powinna mieć klucz podstawowy.

Moja definicja SQL dla kursu studenckiego brzmiała:

CREATE TABLE [dbo].[Student-Course] (
    [StudentID]  VARCHAR (12) NOT NULL,
    [CourseCode] VARCHAR (10) NOT NULL,
    CONSTRAINT [FK_Student-Course_ToCourse] FOREIGN KEY ([Course_Code]) REFERENCES [dbo].[Course] ([Code]) ON DELETE CASCADE,
    CONSTRAINT [FK_Student-Course_ToStudent] FOREIGN KEY ([Student_ID]) REFERENCES [dbo].[Student] ([Id]) ON DELETE CASCADE
);

Uczyniłem parę kluczy obcych kluczem podstawowym tej tabeli i zaktualizowałem do:

CREATE TABLE [dbo].[Student-Course] (
    [StudentID]  VARCHAR (12) NOT NULL,
    [CourseCode] VARCHAR (10) NOT NULL,
    CONSTRAINT [PK_Student-Course] PRIMARY KEY CLUSTERED ([Student_ID] ASC, [Course_Code] ASC),
    CONSTRAINT [FK_Student-Course_ToCourse] FOREIGN KEY ([Course_Code]) REFERENCES [dbo].[Course] ([Code]) ON DELETE CASCADE,
    CONSTRAINT [FK_Student-Course_ToStudent] FOREIGN KEY ([Student_ID]) REFERENCES [dbo].[Student] ([Id]) ON DELETE CASCADE
);

Mam nadzieję, że rozwiąże to problemy niektórych facetów.

Podsumowanie Raja
źródło
To pytanie ma już zbyt wiele odpowiedzi. Co więcej, prawie każda odpowiedź mówi „dodać klucz podstawowy” i jeden robi to w kontekście wiele-do-wielu.
Gert Arnold
Masz rację, ale niektóre osoby dodają dodatkowy identyfikator klucza podstawowego w trzeciej tabeli, co nie jest dobrym podejściem.
Podsumuj Raja
Jak mówi druga odpowiedź.
Gert Arnold