Typ jednostki <typ> nie jest częścią modelu dla bieżącego kontekstu

146

Wchodzę do Entity Framework, ale nie jestem pewien, czy brakuje mi punktu krytycznego w podejściu do kodu.

Używam ogólnego wzorca repozytorium opartego na kodzie z https://genericunitofworkandrepositories.codeplex.com/ i utworzyłem moje jednostki.

Ale kiedy próbuję uzyskać dostęp do podmiotu lub go zmodyfikować, napotykam:

System.InvalidOperationException: Typ jednostki Estate nie jest częścią modelu dla bieżącego kontekstu.

Dzieje się tak, gdy próbuję uzyskać do niego dostęp z mojego repozytorium:

public virtual void Insert(TEntity entity)
{
    ((IObjectState)entity).ObjectState = ObjectState.Added;
    _dbSet.Attach(entity); // <-- The error occurs here
    _context.SyncObjectState(entity);
}

Baza danych (./SQLEXPRESS) jest tworzona dobrze, ale jednostki (tabele) po prostu nie są tworzone podczas uruchamiania.

Zastanawiam się, czy muszę jawnie ustawić mapowanie jednostek? Czy EF nie jest w stanie tego zrobić samodzielnie?

Moja jednostka to:

public class Estate : EntityBase
{
    public int EstateId { get; set; }
    public string Name { get; set; }
} 

Mój kontekst jest taki:

public partial class DimensionWebDbContext : DbContextBase // DbContextBase inherits DbContext
{
    public DimensionWebDbContext() :
        base("DimensionWebContext")
    {
        Database.SetInitializer<DimensionWebDbContext>(new CreateDatabaseIfNotExists<DimensionWebDbContext>());
        Configuration.ProxyCreationEnabled = false;
    }

    public new IDbSet<T> Set<T>() where T : class
    {
        return base.Set<T>();
    }

}

Czy jest jakiś konkretny powód, dla którego występuje ten błąd? Próbowałem włączyć migracje i włączyć automatyczne migracje bez żadnej pomocy.

janhartmann
źródło

Odpowiedzi:

142

Umieść to w swojej DbContextklasie niestandardowej :

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Estate>().ToTable("Estate");
}

Jeśli twoje tabele nie są tworzone podczas uruchamiania, to właśnie dlatego. Musisz powiedzieć o nich DbContext w zastąpieniu metody OnModelCreating.

Możesz tutaj wykonać niestandardowe mapowania na encje lub podzielić je na osobne EntityTypeConfiguration<T>klasy.

danludwig
źródło
1
Dzięki, Dan - to rozwiązuje problem. Teraz tabele są tworzone. Nie ma innego wyjścia, EF nie może tego zrobić samodzielnie? Nie mogę po prostu dodać do obiektu adnotacji [ToTable („Estates”)] lub czegoś w tym rodzaju?
janhartmann
3
Myślę, że może to działać bez zastępowania, OnModelCreatingjeśli twoje encje są w tym samym zestawie co twój DbContext. Nigdy jednak nie używałem adnotacji danych dla encji, więc nie mogę powiedzieć na pewno. Zawsze możesz skanować zespoły w swoim zespole, OnModelCreatingaby znaleźć elementy w innych zespołach i zarejestrować je automatycznie (co robi statyw).
danludwig,
Ach, oczywiście. Dzięki za notatkę o sposobie robienia tego przez statyw, zrobiłem teraz coś podobnego i wydaje się, że działa dobrze. (również dzięki rozszerzeniom refleksji na: github.com/danludwig/Layout3/blob/master/UCosmic.Domain/Api/… ). Teraz potrzebuję tylko, aby znajdował zestawy odwołań zamiast patrzeć przez zespół GetType (). "var assembly = Assembly.Load (" Dimension.Web.Domain ");" nie jest ładna ;-)
janhartmann
A może po prostu przenieś mój nowy / Mapping / folder do mojego projektu Impl zamiast mojej domeny.
janhartmann
@meep lub danludwig. Czy możesz powiedzieć mi więcej o statywie lub udostępnić mi link.
DkAngelito,
73

Najwyraźniej ten błąd jest bardzo ogólny, może mieć wiele przyczyn. W moim przypadku było to następujące: Ciąg połączenia (w pliku Web.config) wygenerowany przez .edmxplik był nieprawidłowy. Po prawie dniu próbowania wszystkiego zmieniłem parametry połączenia z ciągu EF na ciąg ADO.NET. To rozwiązało mój problem.

Na przykład ciąg EF wygląda mniej więcej tak:

<connectionStrings> 
  <add name="BlogContext"  
    connectionString="metadata=res://*/BloggingModel.csdl| 
                               res://*/BloggingModel.ssdl| 
                               res://*/BloggingModel.msl; 
                               provider=System.Data.SqlClient 
                               provider connection string= 
                               &quot;data source=(localdb)\v11.0; 
                               initial catalog=Blogging;
                               integrated security=True; 
                               multipleactiveresultsets=True;&quot;" 
     providerName="System.Data.EntityClient" /> 
</connectionStrings>

A ciąg ADO.NET wygląda następująco:

<connectionStrings>
  <add name="BlogContext"  
        providerName="System.Data.SqlClient"  
        connectionString="Server=.\SQLEXPRESS;Database=Blogging;
        Integrated Security=True;"/> 
</connectionStrings>

Źródło: http://msdn.microsoft.com/nl-nl/data/jj556606.aspx

Christiaan Maks
źródło
17
Mój problem dotyczył również parametrów połączenia. Zmieniłem nazwę mojego modelu danych i ponownie ułożyłem szablony t4, ale zapomniałem zaktualizować metadane (pliki .csdl, .ssdl, .msl) w parametrach połączenia. Twoja odpowiedź pomogła mi to zrozumieć, więc dziękuję!
Vyskol,
4
Jeśli używasz modelu tożsamości do uwierzytelniania, potrzebujesz 2 ciągów połączeń: jeden, „DefaultConnection”, którego nazwę możesz zmienić lub nie i umieścić w swoim publicznym ApplicationDbContext (): base („IdentityDbContext”, throwIfV1Schema: false) {} To właśnie spowodowało mój błąd jak twój (miałem tam ciąg EF). Drugi ciąg połączenia to ten utworzony przez dodanie EF za pomocą kreatora i pyta o parametry parametrów połączenia. Mam nadzieję, że to komuś pomoże.
JustJohn
to samo tutaj. niesamowicie frustrujące
Nick Molyneux
1
Uaktualniam z EF 4.xdo EF 6. Musiałem zregenerować parametry połączenia, aby dodać tabelę ( DatabaseFirst). Nie zauważyłem, że moje połączenie w app.configi w web.configbyły różne. Kiedy przejąłem connectionstringod app.config, zaczęło działać.
CWF
16

Dla mnie problem polegał na tym, że nie uwzględniłem klasy jednostki w moim zestawie db w kontekście struktury jednostki.

public DbSet<ModelName> ModelName { get; set; }
Demodave
źródło
12

Możesz spróbować usunąć tabelę z modelu i dodać ją ponownie. Możesz to zrobić wizualnie, otwierając plik .edmx w Eksploratorze rozwiązań.

Kroki:

  1. Kliknij dwukrotnie plik .edmx w Eksploratorze rozwiązań
  2. Kliknij prawym przyciskiem myszy nagłówek tabeli, który chcesz usunąć, i wybierz „Usuń z modelu”
  3. Teraz ponownie kliknij prawym przyciskiem myszy obszar roboczy i wybierz „Aktualizuj model z bazy danych”.
  4. Dodaj tabelę ponownie z listy tabel
  5. Wyczyść i skompiluj rozwiązanie
Bieg
źródło
8
Najpierw nie ma .edmx w kodzie EF.
Tuukka Haapaniemi
Jednak dałem +1, ponieważ on (lub ktoś inny z tym problemem) mógłby chcieć przemyśleć na nowo, robiąc Code First i zrobić to w ten sposób :)
vapcguy
9

Problem może dotyczyć parametrów połączenia. Upewnij się, że parametry połączenia są przeznaczone dla dostawcy SqlClient, bez elementów metadanych związanych z EntityFramework.

Shawn de Wet
źródło
Było to prawdopodobnie oczywiste dla wielu, ale okazało się to moim problemem (dotyczącym mieszania db-first z code-first). Teraz mogę przestać kręcić kołami, wielkie dzięki!
Bonez024
3

Widziałem ten błąd, gdy istniejąca tabela w bazie danych nie jest odpowiednio odwzorowana na pierwszy model kodu. W szczególności miałem char (1) w tabeli bazy danych i znak w C #. Zmiana modelu na łańcuch rozwiązała problem.

Daniel Leach
źródło
3

Mój problem został rozwiązany przez zaktualizowanie części metadanych parametrów połączenia. Najwyraźniej wskazywał na niewłaściwe odniesienie .csdl / .ssdl / .msl.

ragnarswanson
źródło
Mnie też się to przydarzyło. Skopiowałem łańcuch połączenia EF z innego miejsca i nie zaktualizowałem nazwy modelu w metadanych.
devC
2

Jeszcze jedna rzecz do sprawdzenia w parametrach połączenia - nazwa modelu. Używałem dwóch modeli jednostek, najpierw DB. W konfiguracji skopiowałem połączenie encji dla jednego, zmieniłem jego nazwę i zmieniłem część parametrów połączenia. To, czego nie zmieniłem, to nazwa modelu, więc podczas gdy model jednostki został wygenerowany poprawnie, po zainicjowaniu kontekstu EF szukał w niewłaściwym modelu dla jednostek.

Wygląda na to, że jest zapisane, ale są cztery godziny, na które nie wrócę.

Eddie
źródło
2

Dla mnie problem polegał na tym, że użyłem connection stringwygenerowanego przez ADO.NetModel (.edmx). Zmiana parametrów połączenia rozwiązała mój problem.

FN90
źródło
1

Może to również wystąpić, jeśli używasz utrwalonej pamięci podręcznej modelu, która jest nieaktualna z jakiegoś powodu. Jeśli kontekst został zbuforowany w pliku EDMX w systemie plików (za pośrednictwem DbConfiguration.SetModelStore), wówczas OnModelCreating nigdy nie zostanie wywołany, ponieważ zostanie użyta wersja buforowana. W rezultacie, jeśli w magazynie buforowanym brakuje jednostki, wystąpi powyższy błąd, mimo że parametry połączenia są poprawne, tabela istnieje w bazie danych, a jednostka jest poprawnie skonfigurowana w DbContext.

strickt01
źródło
1

Przekaz był dość jasny, ale na początku go nie zrozumiałem ...

Pracuję z dwoma kontekstami Entity Framework DB sysContexti shardContexttą samą metodą.

Jednostka, którą zmodyfikowałem \ zaktualizowałem, pochodzi z jednego kontekstu, ale potem próbowałem zapisać ją w innym kontekście, w następujący sposób:

invite.uid = user.uid;

sysContext.Entry(invite).State = EntityState.Modified;

sysContext.SaveChanges(); // Got the exception here

ale poprawna wersja powinna wyglądać tak:

invite.uid = user.uid;

shardContext.Entry(invite).State = EntityState.Modified;

shardContext.SaveChanges();

Po przekazaniu jednostki do odpowiedniego kontekstu ten błąd zniknął.

Leniel Maccaferri
źródło
0

Brzmi oczywiste, ale upewnij się, że nie ignorujesz jawnie tego typu:

modelBuilder.Ignore<MyType>();

emragins
źródło
0

mapa jednostki (nawet pustej) dodana do konfiguracji spowoduje, że typ jednostki będzie częścią kontekstu. Mieliśmy obiekt bez związku z innymi obiektami, który został naprawiony za pomocą pustej mapy.

mcfea
źródło
0

jeśli najpierw próbujesz DB, upewnij się, że twoja tabela ma klucz podstawowy

Mahmoud
źródło
0

Wydaje się, że program Visual Studio 2019 powoduje to u mnie. Naprawiłem to, ponownie generując model edmx w 2017 roku.

chinupson
źródło
0

Mam ten sam problem w Entity Framewrok i rozwiązałem go, wykonując następujące czynności:

1-Otwórz swój Model.edmx 2-zmień miejsce na stole (do zmiany w pliku cs) 3-zapisz go

Mam nadzieję, że ci pomogę

Akbar Asghari
źródło
0

Usuń plik .edmx i dodaj go ponownie. Szczególnie, jeśli zaktualizowałeś Entity Framework.

Roy Oliver
źródło
0

Miałem ten sam problem z EntityFrameworkCore, próbując zaktualizować zakres wartości.

To podejście nie zadziałało

  _dbSet.AttachRange(entity);
  _context.Entry(entity).State = EntityState.Modified;
   await _context.SaveChangesAsync().ConfigureAwait(false);

Po dodaniu metody UpdateRange i usunięciu załączania i wpisywania wszystko działa

  _dbSet.UpdateRange(entity);
  await _context.SaveChangesAsync().ConfigureAwait(false);
Okyam
źródło
0

U mnie było to spowodowane tym, że zmieniłem nazwę klasy encji, a kiedy ją wycofałem, było OK.

Iván Kollár
źródło
0

To może być głupie, ale jeśli masz ten błąd tylko w jakiejś tabeli, nie zapomnij wyczyścić swojego projektu i przebudować (może to zaoszczędzić dużo czasu)

LeBigCat
źródło
0

Miałem to

using (var context = new ATImporterContext(DBConnection))
{
    if (GetID(entity).Equals(0))
    {
        context.Set<T>().Add(entity);
    }
    else
    {
        int val = GetID(entity);
        var entry = GetEntryAsync(context, GetID(entity)).ConfigureAwait(false);
        context.Entry(entry).CurrentValues.SetValues(entity);

    }
    
    await context.SaveChangesAsync().ConfigureAwait(false);
}

To było w metodzie asynchronicznej, ale zapomniałem ustawić await przed GetEntryAsync, więc otrzymałem ten sam błąd ...

bifedefrango
źródło