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
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
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 GetColumnName
elementem , 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 { ... }
metodySelect
, 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
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 Author
elementu . 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
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 id
element .
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
Stare zachowanie
IMigrationsModelDiffer
Interfejs API został zdefiniowany przy użyciu polecenia IModel
.
Nowe zachowanie
IMigrationsModelDiffer
Interfejs 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 snapshot
context
:
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 SaveChanges
metody , 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
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, 618
polecenie .
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
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())