Udostępnij za pośrednictwem


Zmiany powodujące niezgodność w programie EF Core 5.0

Następujące zmiany interfejsu API i zachowania mogą powodować przerwanie aktualizacji istniejących aplikacji do programu EF Core 5.0.0.

Podsumowanie

Zmiana powodująca niezgodność Wpływ
Program EF Core 5.0 nie obsługuje programu .NET Framework Średnie
IProperty.GetColumnName() jest teraz przestarzały Średnie
Precyzja i skala są wymagane dla miejsc dziesiętnych Średnie
Wymagana lub niepusta nawigacja od podmiotu zabezpieczeń do zależności ma różne semantyka Średnie
Definiowanie zapytania jest zastępowane metodami specyficznymi dla dostawcy Średnie
Nawigacje referencyjne inne niż null nie są zastępowane przez zapytania Średnie
Funkcja ToView() jest traktowana inaczej przez migracje Średnie
ToTable(null) oznacza typ jednostki jako niemapowany na tabelę Średnie
Usunięto metodę HasGeometricDimension z rozszerzenia SQLite NTS Niska
Azure Cosmos DB: klucz partycji jest teraz dodawany do klucza podstawowego Niska
Azure Cosmos DB: id zmieniono nazwę właściwości na __id Niska
Azure Cosmos DB: bajt[] jest teraz przechowywany jako ciąg base64 zamiast tablicy liczbowej Niska
Azure Cosmos DB: zmieniono nazwy GetPropertyName i SetPropertyName Niska
Generatory wartości są wywoływane, gdy stan jednostki zostanie zmieniony z Odłączone na Niezmienione, Zaktualizowane lub Usunięte Niska
Model IMigrationsModelDiffer używa teraz modelu IRelationalModel Niska
Dyskryminujące są tylko do odczytu Niska
EF specyficzny dla dostawcy. Metody funkcji zgłaszane przez dostawcę InMemory Niska
IndexBuilder.HasName jest teraz przestarzały Niska
Pluralizator jest teraz dołączany do tworzenia szkieletów modeli zaprojektowanych odwrotnie Niska
Baza INavigationBase zastępuje interfejsy INavigation w niektórych interfejsach API w celu obsługi pomijania nawigacji Niska
Niektóre zapytania z skorelowanej kolekcji, które również używają Distinct lub GroupBy nie są już obsługiwane Niska
Używanie kolekcji typu Queryable w projekcji nie jest obsługiwane Niska

Zmiany o średnim wpływie

Program EF Core 5.0 nie obsługuje programu .NET Framework

Problem ze śledzeniem nr 15498

Stare zachowanie

Program EF Core 3.1 jest przeznaczony dla platformy .NET Standard 2.0, która jest obsługiwana przez program .NET Framework.

Nowe zachowanie

Program EF Core 5.0 jest przeznaczony dla platformy .NET Standard 2.1, która nie jest obsługiwana przez program .NET Framework. Oznacza to, że nie można używać programu EF Core 5.0 z aplikacjami .NET Framework.

Dlaczego

Jest to część szerszego ruchu w zespołach platformy .NET mających na celu zjednoczenie pojedynczej platformy docelowej .NET. Aby uzyskać więcej informacji, zobacz przyszłość platformy .NET Standard.

Środki zaradcze

Aplikacje platformy .NET Framework mogą nadal korzystać z programu EF Core 3.1, który jest wersją długoterminową (LTS). Alternatywnie można zaktualizować aplikacje tak, aby korzystały z platformy .NET Core 3.1 lub .NET 5, z których obie obsługują platformę .NET Standard 2.1.

IProperty.GetColumnName() jest teraz przestarzały

Problem ze śledzeniem nr 2266

Stare zachowanie

GetColumnName() zwrócił nazwę kolumny, do którą jest mapowana właściwość.

Nowe zachowanie

GetColumnName() Nadal zwraca nazwę kolumny, do której jest mapowana właściwość, ale to zachowanie jest teraz niejednoznaczne, ponieważ program EF Core 5 obsługuje TPT i jednoczesne mapowanie do widoku lub funkcji, w której te mapowania mogą używać różnych nazw kolumn dla tej samej właściwości.

Dlaczego

Oznaczyliśmy tę metodę jako przestarzałą, aby umożliwić użytkownikom dokładniejsze przeciążenie — GetColumnName(IProperty, StoreObjectIdentifier).

Środki zaradcze

Jeśli typ jednostki jest zawsze mapowany na jedną tabelę i nigdy nie jest mapowany na widoki, funkcje lub wiele tabel, GetColumnBaseName(IReadOnlyProperty) można go użyć w programie EF Core 5.0 i 6.0, aby uzyskać nazwę tabeli. Przykład:

var columnName = property.GetColumnBaseName();

W programie EF Core 7.0 można to ponownie zastąpić nowym GetColumnNameelementem , który zachowuje się tak jak w przypadku prostych mapowań tylko w pojedynczej tabeli.

Jeśli typ jednostki może być mapowany na widoki, funkcje lub wiele tabel, StoreObjectIdentifier należy uzyskać element do tożsamości tabeli, widoku lub funkcji. Można go następnie użyć do pobrania nazwy kolumny dla tego obiektu magazynu. Przykład:

var columnName = property.GetColumnName(StoreObjectIdentifier.Table("Users", null)));

Precyzja i skala są wymagane dla miejsc dziesiętnych

Problem ze śledzeniem nr 19293

Stare zachowanie

Program EF Core zwykle nie ustawiał dokładności i skalowania obiektów SqlParameter . Oznacza to, że pełna precyzja i skala została wysłana do programu SQL Server, w którym momencie program SQL Server zaokrągli się w oparciu o precyzję i skalę kolumny bazy danych.

Nowe zachowanie

Program EF Core ustawia teraz precyzję i skalowanie parametrów przy użyciu wartości skonfigurowanych dla właściwości w modelu EF Core. Oznacza to, że zaokrąglanie odbywa się teraz w programie SqlClient. W związku z tym, jeśli skonfigurowana precyzja i skala nie są zgodne z dokładnością i skalą bazy danych, może ulec zmianie zaokrąglenie widoczne.

Dlaczego

Nowsze funkcje programu SQL Server, w tym Always Encrypted, wymagają, aby aspekty parametrów zostały w pełni określone. Ponadto sqlClient dokonał zmiany w celu zaokrąglenia zamiast obcięć wartości dziesiętnych, co odpowiada zachowaniu programu SQL Server. Dzięki temu program EF Core może ustawić te aspekty bez zmiany zachowania dla poprawnie skonfigurowanych miejsc dziesiętnych.

Środki zaradcze

Zamapuj właściwości dziesiętne przy użyciu nazwy typu, która zawiera precyzję i skalę. Przykład:

public class Blog
{
    public int Id { get; set; }

    [Column(TypeName = "decimal(16, 5)")]
    public decimal Score { get; set; }
}

Możesz też użyć HasPrecision w interfejsach API tworzenia modelu. Przykład:

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>().Property(e => e.Score).HasPrecision(16, 5);
    }

Wymagana lub niepusta nawigacja od podmiotu zabezpieczeń do zależności ma różne semantyka

Problem ze śledzeniem nr 17286

Stare zachowanie

Zgodnie z wymaganiami można skonfigurować tylko nawigacje do podmiotu zabezpieczeń. W związku z tym użycie w RequiredAttribute nawigacji do zależnego (jednostki zawierającej klucz obcy) lub oznaczanie go jako niepustego spowoduje utworzenie klucza obcego w typie definiowania jednostki.

Nowe zachowanie

Po dodaniu obsługi wymaganych zależności można teraz oznaczyć dowolną nawigację referencyjną zgodnie z potrzebami, co oznacza, że w przypadku pokazanym powyżej klucza obcego zostanie zdefiniowany po drugiej stronie relacji, a właściwości nie zostaną oznaczone jako wymagane.

Wywołanie IsRequired przed określeniem końca zależnego jest teraz niejednoznaczne:

modelBuilder.Entity<Blog>()
    .HasOne(b => b.BlogImage)
    .WithOne(i => i.Blog)
    .IsRequired()
    .HasForeignKey<BlogImage>(b => b.BlogForeignKey);

Dlaczego

Nowe zachowanie jest niezbędne do włączenia obsługi wymaganych zależności (zobacz nr 12100).

Środki zaradcze

Usuń RequiredAttribute z nawigacji do zależności i umieść ją zamiast tego na nawigacji do podmiotu zabezpieczeń lub skonfiguruj relację w pliku OnModelCreating:

modelBuilder.Entity<Blog>()
    .HasOne(b => b.BlogImage)
    .WithOne(i => i.Blog)
    .HasForeignKey<BlogImage>(b => b.BlogForeignKey)
    .IsRequired();

Definiowanie zapytania jest zastępowane metodami specyficznymi dla dostawcy

Problem ze śledzeniem nr 18903

Stare zachowanie

Typy jednostek zostały zamapowane na definiowanie zapytań na poziomie podstawowego. Za każdym razem, gdy typ jednostki był używany w katalogu głównym zapytania typu jednostki, został zastąpiony przez definiowanie zapytania dla dowolnego dostawcy.

Nowe zachowanie

Interfejsy API do definiowania zapytania są przestarzałe. Wprowadzono nowe interfejsy API specyficzne dla dostawcy.

Dlaczego

Podczas definiowania zapytań zaimplementowano jako zapytanie zastępcze za każdym razem, gdy w zapytaniu jest używany katalog główny zapytania, wystąpiły pewne problemy:

  • Jeśli zapytanie definiuje typ jednostki przy użyciu new { ... } metody Select , oznacza to, że jako jednostka wymagała dodatkowej pracy i uczyniła ją niespójną ze sposobem, w jaki program EF Core traktuje typy nominalne w zapytaniu.
  • W przypadku dostawców FromSql relacyjnych nadal trzeba przekazać ciąg SQL w formularzu wyrażenia LINQ.

Początkowo definiowanie zapytań zostało wprowadzone jako widoki po stronie klienta, które mają być używane z dostawcą w pamięci dla jednostek bez klucza (podobnie jak w widokach bazy danych w relacyjnych bazach danych). Taka definicja ułatwia testowanie aplikacji względem bazy danych w pamięci. Potem stały się szeroko stosowane, co było przydatne, ale przyniosło niespójne i trudne do zrozumienia zachowanie. Postanowiliśmy więc uprościć koncepcję. Wprowadziliśmy oparte na LINQ definiowanie zapytania wyłącznie do dostawcy w pamięci i traktujemy je inaczej. Aby uzyskać więcej informacji, zobacz ten problem.

Środki zaradcze

W przypadku dostawców relacyjnych użyj ToSqlQuery metody w OnModelCreating pliku i przekaż ciąg SQL do użycia dla typu jednostki. W przypadku dostawcy w pamięci użyj ToInMemoryQuery metody w OnModelCreating pliku i przekaż zapytanie LINQ do użycia dla typu jednostki.

Nawigacje referencyjne inne niż null nie są zastępowane przez zapytania

Problem ze śledzeniem nr 2693

Stare zachowanie

W programie EF Core 3.1 nawigacje odwołujące się chętnie do wartości innych niż null czasami zostaną zastąpione przez wystąpienia jednostek z bazy danych, niezależnie od tego, czy są zgodne wartości kluczy. Jednak w innych przypadkach program EF Core 3.1 zrobi odwrotnie i pozostawi istniejącą wartość inną niż null.

Nowe zachowanie

Począwszy od programu EF Core 5.0, nawigacje referencyjne inne niż null nigdy nie są zastępowane przez wystąpienia zwracane z zapytania.

Należy pamiętać, że chętne inicjowanie nawigacji kolekcji do pustej kolekcji jest nadal obsługiwane.

Dlaczego

Inicjowanie właściwości nawigacji referencyjnej do wystąpienia jednostki "puste" powoduje niejednoznaczny stan. Przykład:

public class Blog
{
     public int Id { get; set; }
     public Author Author { get; set; ) = new Author();
}

Zwykle zapytanie dotyczące blogów i autorów najpierw tworzy Blog wystąpienia, a następnie ustawia odpowiednie Author wystąpienia na podstawie danych zwracanych z bazy danych. Jednak w tym przypadku każda Blog.Author właściwość jest już inicjowana do pustego Authorelementu . Z wyjątkiem programu EF Core nie ma możliwości, aby wiedzieć, że to wystąpienie jest "puste". Dlatego zastąpienie tego wystąpienia może potencjalnie dyskretnie wyrzucić prawidłowe Author. W związku z tym program EF Core 5.0 stale nie zastępuje już zainicjowanej nawigacji.

To nowe zachowanie jest również zgodne z zachowaniem ef6 w większości przypadków, chociaż podczas badania znaleźliśmy również niektóre przypadki niespójności w EF6.

Środki zaradcze

Jeśli ten podział zostanie napotkany, poprawka polega na tym, aby zatrzymać niecierpliwie zainicjowanie właściwości nawigacji referencyjnej.

Funkcja ToView() jest traktowana inaczej przez migracje

Problem ze śledzeniem nr 2725

Stare zachowanie

Wywołanie ToView(string) sprawiło, że migracje ignorowały typ jednostki oprócz mapowania go na widok.

Nowe zachowanie

Teraz ToView(string) oznacza typ jednostki jako niemapowany do tabeli oprócz mapowania go na widok. Spowoduje to pierwszą migrację po uaktualnieniu do programu EF Core 5, aby spróbować usunąć domyślną tabelę dla tego typu jednostki, ponieważ nie jest już ignorowana.

Dlaczego

Program EF Core umożliwia teraz mapowanie typu jednostki na tabelę i widok jednocześnie, więc ToView nie jest już prawidłowym wskaźnikiem, który powinien zostać zignorowany przez migracje.

Środki zaradcze

Użyj następującego kodu, aby oznaczyć zamapowana tabelę jako wykluczona z migracji:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<User>().ToTable("UserView", t => t.ExcludeFromMigrations());
}

ToTable(null) oznacza typ jednostki jako niemapowany na tabelę

Problem ze śledzeniem nr 21172

Stare zachowanie

ToTable(null) spowoduje zresetowanie nazwy tabeli do wartości domyślnej.

Nowe zachowanie

ToTable(null) teraz oznacza typ jednostki jako niemapowany do żadnej tabeli.

Dlaczego

Program EF Core umożliwia teraz mapowanie typu jednostki na tabelę i widok jednocześnie, dlatego ToTable(null) służy do wskazywania, że nie jest mapowany na żadną tabelę.

Środki zaradcze

Użyj następującego kodu, aby zresetować nazwę tabeli do wartości domyślnej, jeśli nie jest ona mapowana na widok lub polecenie DbFunction:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<User>().Metadata.RemoveAnnotation(RelationalAnnotationNames.TableName);
}

Zmiany o niskim wpływie

Usunięto metodę HasGeometricDimension z rozszerzenia SQLite NTS

Problem ze śledzeniem nr 14257

Stare zachowanie

Funkcja HasGeometricDimension została użyta do włączenia dodatkowych wymiarów (Z i M) w kolumnach geometrycznych. Jednak tylko kiedykolwiek miało to wpływ na tworzenie bazy danych. Nie trzeba było określać jej w celu wysyłania zapytań o wartości z dodatkowymi wymiarami. Nie działa również poprawnie podczas wstawiania lub aktualizowania wartości z dodatkowymi wymiarami (zobacz #14257).

Nowe zachowanie

Aby umożliwić wstawianie i aktualizowanie wartości geometrycznych z dodatkowymi wymiarami (Z i M), wymiar należy określić jako część nazwy typu kolumny. Ten interfejs API jest bardziej zbliżony do bazowego zachowania funkcji AddGeometryColumn spatiaLite.

Dlaczego

Użycie funkcji HasGeometricDimension po określeniu wymiaru w typie kolumny jest niepotrzebne i nadmiarowe, dlatego całkowicie usunęliśmy element HasGeometricDimension.

Środki zaradcze

Użyj HasColumnType polecenia , aby określić wymiar:

modelBuilder.Entity<GeoEntity>(
    x =>
    {
        // Allow any GEOMETRY value with optional Z and M values
        x.Property(e => e.Geometry).HasColumnType("GEOMETRYZM");

        // Allow only POINT values with an optional Z value
        x.Property(e => e.Point).HasColumnType("POINTZ");
    });

Azure Cosmos DB: klucz partycji jest teraz dodawany do klucza podstawowego

Problem ze śledzeniem nr 15289

Stare zachowanie

Właściwość klucza partycji została dodana tylko do klucza alternatywnego, który zawiera idelement .

Nowe zachowanie

Właściwość klucza partycji jest teraz również dodawana do klucza podstawowego zgodnie z konwencją.

Dlaczego

Ta zmiana sprawia, że model jest lepiej dopasowany do semantyki usługi Azure Cosmos DB i poprawia wydajność Find niektórych zapytań.

Środki zaradcze

Aby zapobiec dodaniu właściwości klucza partycji do klucza podstawowego, skonfiguruj ją w pliku OnModelCreating.

modelBuilder.Entity<Blog>()
    .HasKey(b => b.Id);

Azure Cosmos DB: id zmieniono nazwę właściwości na __id

Problem ze śledzeniem nr 17751

Stare zachowanie

Właściwość cienia mapowana na id właściwość JSON nosi również nazwę id.

Nowe zachowanie

Właściwość w tle utworzona przez konwencję nosi teraz nazwę __id.

Dlaczego

Ta zmiana sprawia, że jest mniej prawdopodobne, że id właściwość zderza się z istniejącą właściwością w typie jednostki.

Środki zaradcze

Aby wrócić do zachowania w wersji 3.x, skonfiguruj id właściwość w pliku OnModelCreating.

modelBuilder.Entity<Blog>()
    .Property<string>("id")
    .ToJsonProperty("id");

Azure Cosmos DB: bajt[] jest teraz przechowywany jako ciąg base64 zamiast tablicy liczbowej

Problem ze śledzeniem nr 17306

Stare zachowanie

Właściwości bajtu typu[] były przechowywane jako tablica liczbowa.

Nowe zachowanie

Właściwości bajtu typu[] są teraz przechowywane jako ciąg base64.

Dlaczego

Ta reprezentacja bajtów[] lepiej odpowiada oczekiwaniom i jest domyślnym zachowaniem głównych bibliotek serializacji JSON.

Środki zaradcze

Istniejące dane przechowywane jako tablice liczbowe będą nadal prawidłowo wykonywane zapytania, ale obecnie nie ma obsługiwanego sposobu zmiany zachowania wstawiania. Jeśli to ograniczenie blokuje twój scenariusz, dodaj komentarz do tego problemu

Azure Cosmos DB: zmieniono nazwy GetPropertyName i SetPropertyName

Problem ze śledzeniem nr 17874

Stare zachowanie

Wcześniej wywoływano GetPropertyName metody rozszerzenia i SetPropertyName

Nowe zachowanie

Stary interfejs API został usunięty i dodano nowe metody: GetJsonPropertyName, SetJsonPropertyName

Dlaczego

Ta zmiana usuwa niejednoznaczność wokół tego, co konfigurują te metody.

Środki zaradcze

Użyj nowego interfejsu API.

Generatory wartości są wywoływane, gdy stan jednostki zostanie zmieniony z Odłączone na Niezmienione, Zaktualizowane lub Usunięte

Problem ze śledzeniem nr 15289

Stare zachowanie

Generatory wartości były wywoływane tylko wtedy, gdy stan jednostki zmienił się na Dodano.

Nowe zachowanie

Generatory wartości są teraz wywoływane, gdy stan jednostki zostanie zmieniony z Odłączone na Niezmienione, Zaktualizowane lub Usunięte, a właściwość zawiera wartości domyślne.

Dlaczego

Ta zmiana była konieczna, aby ulepszyć środowisko pracy z właściwościami, które nie są utrwalane w magazynie danych i mają zawsze wygenerowaną wartość na kliencie.

Środki zaradcze

Aby zapobiec wywoływaniu generatora wartości, przypisz wartość inną niż domyślna do właściwości przed zmianą stanu.

Model IMigrationsModelDiffer używa teraz modelu IRelationalModel

Problem ze śledzeniem #20305

Stare zachowanie

IMigrationsModelDiffer Interfejs API został zdefiniowany przy użyciu polecenia IModel.

Nowe zachowanie

IMigrationsModelDifferInterfejs API używa teraz .IRelationalModel Jednak migawka modelu nadal zawiera tylko IModel ten kod jest częścią aplikacji, a program Entity Framework nie może go zmienić bez wprowadzania większych zmian powodujących niezgodność.

Dlaczego

IRelationalModel jest nowo dodaną reprezentacją schematu bazy danych. Używanie jej do znajdowania różnic jest szybsze i dokładniejsze.

Środki zaradcze

Użyj następującego kodu, aby porównać model z modelu z snapshotcontext:

var dependencies = context.GetService<ProviderConventionSetBuilderDependencies>();
var relationalDependencies = context.GetService<RelationalConventionSetBuilderDependencies>();

var typeMappingConvention = new TypeMappingConvention(dependencies);
typeMappingConvention.ProcessModelFinalizing(((IConventionModel)modelSnapshot.Model).Builder, null);

var relationalModelConvention = new RelationalModelConvention(dependencies, relationalDependencies);
var sourceModel = relationalModelConvention.ProcessModelFinalized(snapshot.Model);

var modelDiffer = context.GetService<IMigrationsModelDiffer>();
var hasDifferences = modelDiffer.HasDifferences(
    ((IMutableModel)sourceModel).FinalizeModel().GetRelationalModel(),
    context.Model.GetRelationalModel());

Planujemy ulepszyć to środowisko w wersji 6.0 (zobacz #22031)

Dyskryminujące są tylko do odczytu

Problem ze śledzeniem nr 21154

Stare zachowanie

Można było zmienić wartość dyskryminującą przed wywołaniem SaveChanges

Nowe zachowanie

W powyższym przypadku zostanie zgłoszony wyjątek.

Dlaczego

Program EF nie oczekuje, że typ jednostki zmieni się podczas śledzenia, więc zmiana wartości dyskryminującej pozostawia kontekst w stanie niespójnym, co może spowodować nieoczekiwane zachowanie.

Środki zaradcze

Jeśli zmiana wartości dyskryminującej jest konieczna, a kontekst zostanie usunięty natychmiast po wywołaniu SaveChangesmetody , dyskryminujące mogą być modyfikowalne:

modelBuilder.Entity<BaseEntity>()
    .Property<string>("Discriminator")
    .Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Save);

EF specyficzny dla dostawcy. Metody funkcji zgłaszane przez dostawcę InMemory

Problem ze śledzeniem #20294

Stare zachowanie

EF specyficzny dla dostawcy. Metody funkcji zawierały implementację wykonywania klienta, co pozwoliło na ich wykonanie u dostawcy InMemory. Na przykład EF.Functions.DateDiffDay jest to metoda specyficzna dla programu Sql Server, która pracowała nad dostawcą InMemory.

Nowe zachowanie

Metody specyficzne dla dostawcy zostały zaktualizowane w celu zgłoszenia wyjątku w treści metody w celu zablokowania ich oceny po stronie klienta.

Dlaczego

Metody specyficzne dla dostawcy są mapowania na funkcję bazy danych. Obliczenia wykonywane przez funkcję mapowanej bazy danych nie zawsze mogą być replikowane po stronie klienta w LINQ. Może to spowodować różnicę wyniku z serwera podczas wykonywania tej samej metody na kliencie. Ponieważ te metody są używane w linQ do tłumaczenia na określone funkcje bazy danych, nie muszą być oceniane po stronie klienta. Ponieważ dostawca InMemory jest inną bazą danych, te metody nie są dostępne dla tego dostawcy. Próba wykonania ich dla dostawcy InMemory lub innego dostawcy, który nie tłumaczy tych metod, zgłasza wyjątek.

Środki zaradcze

Ponieważ nie ma możliwości dokładnego naśladowania zachowania funkcji bazy danych, należy przetestować zapytania zawierające je względem tej samej bazy danych co w środowisku produkcyjnym.

IndexBuilder.HasName jest teraz przestarzały

Problem ze śledzeniem nr 21089

Stare zachowanie

Wcześniej można zdefiniować tylko jeden indeks dla danego zestawu właściwości. Nazwa bazy danych indeksu została skonfigurowana przy użyciu elementu IndexBuilder.HasName.

Nowe zachowanie

Wiele indeksów jest teraz dozwolonych w tym samym zestawie lub właściwościach. Te indeksy są teraz rozróżniane przez nazwę w modelu. Zgodnie z konwencją nazwa modelu jest używana jako nazwa bazy danych; można go również skonfigurować niezależnie przy użyciu hasDatabaseName.

Dlaczego

W przyszłości chcemy włączyć zarówno indeksy rosnące, jak i malejące lub indeksy z różnymi sortowaniami w tym samym zestawie właściwości. Ta zmiana przenosi nas kolejny krok w tym kierunku.

Środki zaradcze

Każdy kod, który wcześniej wywołuje element IndexBuilder.HasName, powinien zostać zaktualizowany, aby wywołać metodę HasDatabaseName.

Jeśli projekt zawiera migracje wygenerowane przed programem EF Core w wersji 2.0.0, możesz bezpiecznie zignorować ostrzeżenie w tych plikach i pominąć je, dodając #pragma warning disable 612, 618polecenie .

Pluralizator jest teraz dołączany do tworzenia szkieletów modeli zaprojektowanych odwrotnie

Problem ze śledzeniem nr 11160

Stare zachowanie

Wcześniej trzeba było zainstalować oddzielny pakiet pluralizatora w celu gromadzenia nazw nawigacji DbSet i kolekcji oraz tworzenia pojedynczych nazw tabel podczas tworzenia szkieletu dbContext i typów jednostek przez odwrotną inżynierię schematu bazy danych.

Nowe zachowanie

Program EF Core zawiera teraz mnogię, która korzysta z biblioteki Humanizer . Jest to ta sama biblioteka, która używa programu Visual Studio do rekomendowania nazw zmiennych.

Dlaczego

Używanie w liczbie mnogiej wyrazów dla właściwości kolekcji i pojedynczych formularzy dla typów i właściwości referencyjnych jest idiomatyczne na platformie .NET.

Środki zaradcze

Aby wyłączyć mnogię, użyj --no-pluralize opcji włączonej dotnet ef dbcontext scaffold lub -NoPluralize przełącznika .Scaffold-DbContext

Baza INavigationBase zastępuje interfejsy INavigation w niektórych interfejsach API w celu obsługi pomijania nawigacji

Problem ze śledzeniem nr 2568

Stare zachowanie

Program EF Core przed wersją 5.0 obsługiwał tylko jedną formę właściwości nawigacji reprezentowanej INavigation przez interfejs.

Nowe zachowanie

Program EF Core 5.0 wprowadza relacje wiele-do-wielu, które używają "pomijania nawigacji". Są one reprezentowane przez ISkipNavigation interfejs, a większość funkcji INavigation została wypchnięta do wspólnego interfejsu podstawowego: INavigationBase.

Dlaczego

Większość funkcji między normalnymi i pomijaniami nawigacji jest taka sama. Jednak pomiń nawigacje mają inną relację z kluczami obcymi niż normalne nawigacje, ponieważ zaangażowane elementy FKs nie znajdują się bezpośrednio na końcu relacji, ale raczej w jednostce sprzężenia.

Środki zaradcze

W wielu przypadkach aplikacje mogą przełączyć się na korzystanie z nowego interfejsu podstawowego bez innych zmian. Jednak w przypadkach, gdy nawigacja jest używana do uzyskiwania dostępu do właściwości klucza obcego, kod aplikacji powinien być ograniczony tylko do normalnych nawigacji lub zaktualizowany, aby wykonać odpowiednie czynności zarówno dla normalnych, jak i pomijanych nawigacji.

Niektóre zapytania z skorelowanej kolekcji, które również używają Distinct lub GroupBy nie są już obsługiwane

Problem ze śledzeniem nr 15873

Stare zachowanie

Wcześniej zapytania obejmujące skorelowane kolekcje, a następnie GroupBy, a także niektóre zapytania, za pomocą których Distinct mogliśmy wykonać.

Przykład grupowania według:

context.Parents
    .Select(p => p.Children
        .GroupBy(c => c.School)
        .Select(g => g.Key))

Distinct przykład — w szczególności Distinct zapytania, w których projekcja wewnętrzna kolekcji nie zawiera klucza podstawowego:

context.Parents
    .Select(p => p.Children
        .Select(c => c.School)
        .Distinct())

Te zapytania mogą zwracać nieprawidłowe wyniki, jeśli kolekcja wewnętrzna zawiera wszelkie duplikaty, ale działała poprawnie, jeśli wszystkie elementy w kolekcji wewnętrznej były unikatowe.

Nowe zachowanie

Te zapytania nie są już obsługiwane. Zgłaszany jest wyjątek wskazujący, że nie mamy wystarczającej ilości informacji, aby poprawnie skompilować wyniki.

Dlaczego

W przypadku scenariuszy skorelowanej kolekcji musimy znać klucz podstawowy jednostki, aby przypisać jednostki kolekcji do odpowiedniego elementu nadrzędnego. Jeśli kolekcja wewnętrzna nie jest używana GroupBy lub Distinct, brak klucza podstawowego można po prostu dodać do projekcji. Jednak w przypadku GroupBy elementu i Distinct nie można go zrobić, ponieważ spowoduje to zmianę wyniku GroupBy operacji lub Distinct .

Środki zaradcze

Zastąp ponownie zapytanie, aby nie używać GroupBy kolekcji wewnętrznej ani Distinct wykonywać tych operacji na kliencie.

context.Parents
    .Select(p => p.Children.Select(c => c.School))
    .ToList()
    .Select(x => x.GroupBy(c => c).Select(g => g.Key))
context.Parents
    .Select(p => p.Children.Select(c => c.School))
    .ToList()
    .Select(x => x.Distinct())

Używanie kolekcji typu Queryable w projekcji nie jest obsługiwane

Problem ze śledzeniem nr 16314

Stare zachowanie

Wcześniej można było użyć kolekcji typu Queryable wewnątrz projekcji w niektórych przypadkach, na przykład jako argument konstruktora List<T> :

context.Blogs
    .Select(b => new List<Post>(context.Posts.Where(p => p.BlogId == b.Id)))

Nowe zachowanie

Te zapytania nie są już obsługiwane. Zgłaszany jest wyjątek wskazujący, że nie można utworzyć obiektu typu Queryable i sugerując, jak można to naprawić.

Dlaczego

Nie można zmaterializować obiektu typu Queryable, więc zamiast tego zostaną one automatycznie utworzone przy użyciu List<T> typu. Często spowodowałoby to wyjątek z powodu niezgodności typów, co nie było bardzo jasne i może być zaskakujące dla niektórych użytkowników. Postanowiliśmy rozpoznać wzorzec i zgłosić bardziej znaczący wyjątek.

Środki zaradcze

Dodaj ToList() wywołanie po obiekcie Queryable w projekcji:

context.Blogs.Select(b => context.Posts.Where(p => p.BlogId == b.Id).ToList())