Zmiany powodujące niezgodność zawarte w programie EF Core 3.x
Następujące zmiany interfejsu API i zachowania mogą uszkodzić istniejące aplikacje podczas uaktualniania ich do wersji 3.x. Zmiany, które spodziewamy się mieć wpływ tylko na dostawców baz danych, są udokumentowane w obszarze zmiany dostawcy.
Podsumowanie
Zmiany o dużym wpływie
Zapytania LINQ nie są już oceniane na kliencie
Problem ze śledzeniem nr 14935Zobacz również problem nr 12795
Stare zachowanie
Przed wersją 3.0, gdy program EF Core nie może przekonwertować wyrażenia będącego częścią zapytania na sql lub parametr, automatycznie ocenił wyrażenie na kliencie. Domyślnie ocena klienta potencjalnie kosztownych wyrażeń wyzwoliła ostrzeżenie.
Nowe zachowanie
Począwszy od wersji 3.0, program EF Core zezwala na ocenę na kliencie tylko wyrażeń w projekcji najwyższego poziomu (ostatnie Select()
wywołanie zapytania).
Jeśli wyrażenia w żadnej innej części zapytania nie mogą być konwertowane na sql lub parametr, zgłaszany jest wyjątek.
Dlaczego
Automatyczna ocena klienta zapytań umożliwia wykonywanie wielu zapytań, nawet jeśli nie można przetłumaczyć ważnych części zapytań.
To zachowanie może spowodować nieoczekiwane i potencjalnie szkodliwe zachowanie, które może stać się widoczne tylko w środowisku produkcyjnym.
Na przykład warunek w Where()
wywołaniu, którego nie można przetłumaczyć, może spowodować przeniesienie wszystkich wierszy z tabeli z serwera bazy danych oraz filtr do zastosowania na kliencie.
Taka sytuacja może być łatwo niewykryta, jeśli tabela zawiera tylko kilka wierszy podczas programowania, ale mocno uderza, gdy aplikacja przechodzi do środowiska produkcyjnego, gdzie tabela może zawierać miliony wierszy.
Ostrzeżenia dotyczące oceny klienta okazały się również zbyt łatwe do zignorowania podczas opracowywania.
Poza tym automatyczna ocena klienta może prowadzić do problemów, w których poprawa tłumaczenia zapytań dla określonych wyrażeń spowodowała niezamierzone zmiany powodujące niezgodność między wydaniami.
Środki zaradcze
Jeśli nie można w pełni przetłumaczyć zapytania, napisz ponownie zapytanie w formularzu, który można przetłumaczyć, lub użyj AsEnumerable()
metody , ToList()
lub podobnej do jawnego przywrócenia danych do klienta, gdzie można go dalej przetwarzać przy użyciu linQ-to-Objects.
Zmiany o średnim wpływie
Platforma Entity Framework Core nie jest już częścią platformy udostępnionej ASP.NET Core
Śledzenie anonsów problemów nr 325
Stare zachowanie
Przed ASP.NET Core 3.0, po dodaniu odwołania do pakietu do Microsoft.AspNetCore.App
programu lub Microsoft.AspNetCore.All
, będzie to obejmować program EF Core i niektórych dostawców danych ef Core, takich jak dostawca programu SQL Server.
Nowe zachowanie
Począwszy od wersji 3.0, platforma udostępniona ASP.NET Core nie obejmuje platformy EF Core ani żadnych dostawców danych platformy EF Core.
Dlaczego
Przed tą zmianą uzyskanie programu EF Core wymaga różnych kroków w zależności od tego, czy aplikacja docelowa ASP.NET Core i SQL Server, czy nie. Ponadto uaktualnienie ASP.NET Core wymusiło uaktualnienie platformy EF Core i dostawcy programu SQL Server, co nie zawsze jest pożądane.
Dzięki tej zmianie środowisko pobierania platformy EF Core jest takie samo we wszystkich dostawcach, obsługiwanych implementacjach platformy .NET i typach aplikacji. Deweloperzy mogą teraz kontrolować dokładnie, kiedy dostawcy danych EF Core i EF Core są uaktualniani.
Środki zaradcze
Aby użyć programu EF Core w aplikacji ASP.NET Core 3.0 lub dowolnej innej obsługiwanej aplikacji, jawnie dodaj odwołanie do pakietu do dostawcy bazy danych EF Core, którego będzie używać aplikacja.
Narzędzie wiersza polecenia platformy EF Core dotnet ef nie jest już częścią zestawu .NET Core SDK
Problem ze śledzeniem nr 14016
Stare zachowanie
Przed 3.0 dotnet ef
narzędzie zostało dołączone do zestawu .NET Core SDK i było łatwo dostępne do użycia z poziomu wiersza polecenia z dowolnego projektu bez konieczności wykonywania dodatkowych kroków.
Nowe zachowanie
Począwszy od wersji 3.0, zestaw .NET SDK nie zawiera dotnet ef
narzędzia, więc zanim będzie można go użyć, musisz jawnie zainstalować go jako narzędzie lokalne lub globalne.
Dlaczego
Ta zmiana pozwala nam rozpowszechniać i aktualizować dotnet ef
jako zwykłe narzędzie interfejsu wiersza polecenia platformy .NET w pakiecie NuGet, zgodnie z faktem, że program EF Core 3.0 jest również zawsze dystrybuowany jako pakiet NuGet.
Środki zaradcze
Aby móc zarządzać migracjami lub szkieletami DbContext
programu , zainstaluj dotnet-ef
jako narzędzie globalne:
dotnet tool install --global dotnet-ef
Narzędzie lokalne można również uzyskać podczas przywracania zależności projektu, który deklaruje ją jako zależność narzędziową przy użyciu pliku manifestu narzędzia.
Zmiany o niskim wpływie
Zmieniono nazwy z baz danychSql, ExecuteSql i ExecuteSqlAsync
Problem ze śledzeniem nr 10996
Ważne
ExecuteSqlCommand
i ExecuteSqlCommandAsync
są przestarzałe. Zamiast tego użyj tych metod.
Stare zachowanie
Przed programem EF Core 3.0 te nazwy metod zostały przeciążone do pracy z normalnym ciągiem lub ciągiem, który powinien być interpolowany do języka SQL i parametrów.
Nowe zachowanie
Począwszy od programu EF Core 3.0, użyj polecenia FromSqlRaw
, ExecuteSqlRaw
i ExecuteSqlRawAsync
, aby utworzyć sparametryzowane zapytanie, w którym parametry są przekazywane oddzielnie od ciągu zapytania.
Na przykład:
context.Products.FromSqlRaw(
"SELECT * FROM Products WHERE Name = {0}",
product.Name);
Użyj FromSqlInterpolated
, ExecuteSqlInterpolated
i ExecuteSqlInterpolatedAsync
, aby utworzyć sparametryzowane zapytanie, w którym parametry są przekazywane jako część ciągu zapytania interpolowanego.
Na przykład:
context.Products.FromSqlInterpolated(
$"SELECT * FROM Products WHERE Name = {product.Name}");
Należy pamiętać, że oba powyższe zapytania spowodują wygenerowanie tego samego sparametryzowanego kodu SQL z tymi samymi parametrami SQL.
Dlaczego
Takie przeciążenia metody ułatwiają przypadkowe wywołanie metody nieprzetworzonego ciągu, gdy intencją było wywołanie metody ciągów interpolowanych i odwrotnie. Może to spowodować, że zapytania nie są sparametryzowane, gdy powinny być.
Środki zaradcze
Przełącz się, aby użyć nowych nazw metod.
Metoda FromSql, jeśli jest używana z procedurą składowaną, nie może składać się
Problem ze śledzeniem nr 15392
Stare zachowanie
Przed programem EF Core 3.0 metoda FromSql próbowała wykryć, czy przekazany program SQL może się składać. To zrobiło ocenę klienta, gdy sql nie było komponowalne, jak procedura składowana. Poniższe zapytanie działało, uruchamiając procedurę składowaną na serwerze i wykonując operację FirstOrDefault po stronie klienta.
context.Products.FromSqlRaw("[dbo].[Ten Most Expensive Products]").FirstOrDefault();
Nowe zachowanie
Począwszy od programu EF Core 3.0, program EF Core nie spróbuje przeanalizować bazy danych SQL. Więc jeśli komponujesz po fromSqlRaw/FromSqlInterpolated, program EF Core utworzy sql, powodując zapytanie podrzędne. Dlatego jeśli używasz procedury składowanej ze składem, otrzymasz wyjątek dla nieprawidłowej składni SQL.
Dlaczego
Program EF Core 3.0 nie obsługuje automatycznej oceny klienta, ponieważ był podatny na błędy, jak wyjaśniono tutaj.
Środki zaradcze
Jeśli używasz procedury składowanej w metodzie FromSqlRaw/FromSqlInterpolated, wiesz, że nie można jej skomponować, więc możesz dodać AsEnumerable
/AsAsyncEnumerable
bezpośrednio po wywołaniu metody FromSql, aby uniknąć jakiejkolwiek kompozycji po stronie serwera.
context.Products.FromSqlRaw("[dbo].[Ten Most Expensive Products]").AsEnumerable().FirstOrDefault();
Metody FromSql można określić tylko dla katalogów głównych zapytań
Problem ze śledzeniem nr 15704
Stare zachowanie
Przed programem EF Core 3.0 FromSql
można określić metodę w dowolnym miejscu w zapytaniu.
Nowe zachowanie
Począwszy od programu EF Core 3.0, nowe FromSqlRaw
metody i FromSqlInterpolated
(które zastępują FromSql
) można określić tylko dla katalogów głównych zapytań, tj. bezpośrednio w obiekcie DbSet<>
. Próba określenia ich w dowolnym miejscu spowoduje błąd kompilacji.
Dlaczego
Określanie FromSql
dowolnego miejsca innego niż na obiekcie nie miało żadnego dodatkowego DbSet
znaczenia lub wartości dodanej i może spowodować niejednoznaczność w niektórych scenariuszach.
Środki zaradcze
FromSql
wywołania powinny być przenoszone bezpośrednio na DbSet
element, do którego mają zastosowanie.
Zapytania śledzenia nie wykonują już rozpoznawania tożsamości
Problem ze śledzeniem nr 13518
Stare zachowanie
Przed programem EF Core 3.0 to samo wystąpienie jednostki będzie używane dla każdego wystąpienia jednostki o danym typie i identyfikatorze. Jest to zgodne z zachowaniem śledzenia zapytań. Poniższe przykładowe zapytanie:
var results = context.Products.Include(e => e.Category).AsNoTracking().ToList();
zwraca to samo Category
wystąpienie dla każdego Product
, który jest skojarzony z daną kategorią.
Nowe zachowanie
Począwszy od programu EF Core 3.0, różne wystąpienia jednostek zostaną utworzone, gdy jednostka o danym typie i identyfikatorze zostanie napotkana w różnych miejscach na zwracanym grafie. Na przykład powyższe zapytanie zwróci nowe Category
wystąpienie dla każdego Product
nawet wtedy, gdy dwa produkty są skojarzone z tą samą kategorią.
Dlaczego
Rozpoznawanie tożsamości (czyli określenie, że jednostka ma ten sam typ i identyfikator co wcześniej napotkana jednostka), dodaje dodatkowe obciążenie związane z wydajnością i pamięcią. Zwykle jest to sprzeczne z tym, dlaczego zapytania bez śledzenia są używane w pierwszej kolejności. Ponadto podczas gdy rozpoznawanie tożsamości może być czasami przydatne, nie jest konieczne, jeśli jednostki mają być serializowane i wysyłane do klienta, co jest powszechne w przypadku zapytań bez śledzenia.
Środki zaradcze
Użyj zapytania śledzenia, jeśli jest wymagane rozpoznawanie tożsamości.
Tymczasowe wartości klucza nie są już ustawiane na wystąpienia jednostek
Problem ze śledzeniem nr 12378
Stare zachowanie
Przed programem EF Core 3.0 wartości tymczasowe zostały przypisane do wszystkich właściwości klucza, które później miały rzeczywistą wartość wygenerowaną przez bazę danych. Zazwyczaj te wartości tymczasowe były dużą liczbą ujemną.
Nowe zachowanie
Począwszy od wersji 3.0, program EF Core przechowuje tymczasową wartość klucza w ramach informacji śledzenia jednostki i pozostawia właściwość klucza bez zmian.
Dlaczego
Ta zmiana została wprowadzona, aby zapobiec błędnemu utracie wartości kluczy tymczasowych, gdy jednostka, która została wcześniej śledzona przez niektóre DbContext
wystąpienie, zostanie przeniesiona do innego DbContext
wystąpienia.
Środki zaradcze
Aplikacje, które przypisują wartości klucza podstawowego do kluczy obcych w celu tworzenia skojarzeń między jednostkami, mogą zależeć od starego zachowania, jeśli klucze podstawowe są generowane i należą do jednostek w Added
stanie.
Można tego uniknąć, wykonując następujące czynności:
- Nieużywaj kluczy generowanych przez magazyn.
- Ustawianie właściwości nawigacji w celu tworzenia relacji zamiast ustawiania wartości klucza obcego.
- Uzyskaj rzeczywiste wartości klucza tymczasowego z informacji śledzenia jednostki.
Na przykład funkcja zwróci wartość tymczasową,
context.Entry(blog).Property(e => e.Id).CurrentValue
mimo żeblog.Id
sama nie została ustawiona.
DetectChanges honoruje wartości kluczy generowanych przez magazyn
Problem ze śledzeniem nr 14616
Stare zachowanie
Przed programem EF Core 3.0 nieśledzony obiekt znaleziony DetectChanges
przez zostanie śledzony w Added
stanie i wstawiony jako nowy wiersz po SaveChanges
wywołaniu.
Nowe zachowanie
Począwszy od programu EF Core 3.0, jeśli jednostka używa wygenerowanych wartości klucza i ustawiono pewną wartość klucza, jednostka zostanie śledzona w Modified
stanie.
Oznacza to, że zakłada się, że istnieje wiersz dla jednostki i zostanie zaktualizowany po SaveChanges
wywołaniu.
Jeśli wartość klucza nie jest ustawiona lub typ jednostki nie używa wygenerowanych kluczy, nowa jednostka będzie nadal śledzona tak jak Added
w poprzednich wersjach.
Dlaczego
Ta zmiana została wprowadzona, aby ułatwić i bardziej spójną pracę z odłączonym grafami jednostek podczas korzystania z kluczy generowanych przez magazyn.
Środki zaradcze
Ta zmiana może spowodować przerwanie aplikacji, jeśli typ jednostki jest skonfigurowany do używania wygenerowanych kluczy, ale wartości kluczy są jawnie ustawiane dla nowych wystąpień. Poprawka polega na jawnym skonfigurowaniu właściwości klucza, aby nie używać wygenerowanych wartości. Na przykład za pomocą płynnego interfejsu API:
modelBuilder
.Entity<Blog>()
.Property(e => e.Id)
.ValueGeneratedNever();
Lub z adnotacjami danych:
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public string Id { get; set; }
Usunięcia kaskadowe są teraz wykonywane natychmiast domyślnie
Problem ze śledzeniem nr 10114
Stare zachowanie
Przed 3.0 program EF Core zastosował akcje kaskadowe (usuwanie jednostek zależnych po usunięciu wymaganego podmiotu zabezpieczeń lub zerwaniu relacji z wymaganym podmiotem zabezpieczeń) dopiero po wywołaniu funkcji SaveChanges.
Nowe zachowanie
Począwszy od wersji 3.0, program EF Core stosuje akcje kaskadowe natychmiast po wykryciu warunku wyzwalania.
Na przykład wywołanie metody context.Remove()
w celu usunięcia jednostki głównej spowoduje natychmiastowe ustawienie Deleted
wszystkich powiązanych powiązanych wymaganych zależności.
Dlaczego
Ta zmiana została wprowadzona w celu ulepszenia środowiska dla scenariuszy wiązania i inspekcji danych, w których ważne jest, aby zrozumieć, które jednostki zostaną usunięte przed SaveChanges
wywołaniem.
Środki zaradcze
Poprzednie zachowanie można przywrócić za pomocą ustawień w systemie context.ChangeTracker
.
Na przykład:
context.ChangeTracker.CascadeDeleteTiming = CascadeTiming.OnSaveChanges;
context.ChangeTracker.DeleteOrphansTiming = CascadeTiming.OnSaveChanges;
Trwa ładowanie powiązanych jednostek w jednym zapytaniu
Problem ze śledzeniem nr 18022
Stare zachowanie
Przed 3.0 chętne ładowanie nawigacji kolekcji za pośrednictwem Include
operatorów spowodowało wygenerowanie wielu zapytań w relacyjnej bazie danych, po jednym dla każdego powiązanego typu jednostki.
Nowe zachowanie
Począwszy od wersji 3.0, platforma EF Core generuje pojedyncze zapytanie z numerami JOIN w relacyjnych bazach danych.
Dlaczego
Wykonywanie wielu zapytań w celu zaimplementowania pojedynczego zapytania LINQ spowodowało wiele problemów, w tym negatywną wydajność, ponieważ wiele pasków baz danych było niezbędnych, a problemy z współistnieniem danych, ponieważ każde zapytanie może obserwować inny stan bazy danych.
Środki zaradcze
Chociaż technicznie nie jest to zmiana powodująca niezgodność, może to mieć znaczący wpływ na wydajność aplikacji, gdy pojedyncze zapytanie zawiera dużą liczbę operatorów Include
w nawigacji kolekcji. Zobacz ten komentarz , aby uzyskać więcej informacji i uzyskać bardziej wydajne pisanie zapytań.
**
Funkcja DeleteBehavior.Restrict ma semantykę czystszą
Problem ze śledzeniem nr 12661
Stare zachowanie
Przed 3.0 DeleteBehavior.Restrict
utworzono klucze obce w bazie danych za pomocą Restrict
semantyki, ale także zmieniono poprawkę wewnętrzną w sposób nieoczywisty.
Nowe zachowanie
Począwszy od wersji 3.0, zapewnia, DeleteBehavior.Restrict
że klucze obce są tworzone za pomocą Restrict
semantyki — to znaczy bez kaskadowych— nie ma wpływu na naruszenie ograniczeń — bez wpływu również na poprawkę wewnętrzną ef.
Dlaczego
Ta zmiana została wprowadzona, aby poprawić środowisko do korzystania DeleteBehavior
w intuicyjny sposób, bez nieoczekiwanych skutków ubocznych.
Środki zaradcze
Poprzednie zachowanie można przywrócić przy użyciu polecenia DeleteBehavior.ClientNoAction
.
Typy zapytań są konsolidowane przy użyciu typów jednostek
Problem ze śledzeniem nr 14194
Stare zachowanie
Przed programem EF Core 3.0 typy zapytań były sposobem wykonywania zapytań dotyczących danych, które nie definiują klucza podstawowego w sposób ustrukturyzowany. Oznacza to, że typ zapytania był używany do mapowania typów jednostek bez kluczy (najprawdopodobniej z widoku, ale prawdopodobnie z tabeli), podczas gdy zwykły typ jednostki był używany, gdy klucz był dostępny (bardziej prawdopodobne z tabeli, ale prawdopodobnie z widoku).
Nowe zachowanie
Typ zapytania staje się teraz tylko typem jednostki bez klucza podstawowego. Typy jednostek bez klucza mają taką samą funkcjonalność jak typy zapytań w poprzednich wersjach.
Dlaczego
Ta zmiana została wprowadzona w celu zmniejszenia nieporozumień związanych z celem typów zapytań. W szczególności są to typy jednostek bez klucza i są one z natury tylko do odczytu z tego powodu, ale nie powinny być używane tylko dlatego, że typ jednostki musi być tylko do odczytu. Podobnie są one często mapowane na widoki, ale jest to tylko dlatego, że widoki często nie definiują kluczy.
Środki zaradcze
Następujące części interfejsu API są teraz przestarzałe:
ModelBuilder.Query<>()
— Zamiast tegoModelBuilder.Entity<>().HasNoKey()
należy wywołać funkcję , aby oznaczyć typ jednostki jako bez kluczy. Nadal nie zostanie to skonfigurowane zgodnie z konwencją, aby uniknąć błędnej konfiguracji, gdy klucz podstawowy jest oczekiwany, ale nie jest zgodny z konwencją.DbQuery<>
- Zamiast tegoDbSet<>
należy użyć.DbContext.Query<>()
- Zamiast tegoDbContext.Set<>()
należy użyć.IQueryTypeConfiguration<TQuery>
- Zamiast tegoIEntityTypeConfiguration<TEntity>
należy użyć.
Uwaga
Ze względu na problem w wersji 3.x podczas wykonywania zapytań dotyczących jednostek bez klucza, które mają wszystkie właściwości ustawione na null
null
obiekt, zostaną zwrócone zamiast jednostki, jeśli ten problem ma zastosowanie do danego scenariusza, dodaj również logikę do obsługi null
wyników.
Zmieniono interfejs API konfiguracji dla relacji typu należącego do użytkownika
Problem ze śledzeniem #12444Problem ze śledzeniem #9148Problem ze śledzeniem #14153
Stare zachowanie
Przed programem EF Core 3.0 konfiguracja relacji własności została wykonana bezpośrednio po wywołaniu OwnsOne
lub OwnsMany
.
Nowe zachowanie
Począwszy od programu EF Core 3.0, istnieje teraz płynny interfejs API umożliwiający skonfigurowanie właściwości nawigacji dla właściciela przy użyciu polecenia WithOwner()
.
Na przykład:
modelBuilder.Entity<Order>.OwnsOne(e => e.Details).WithOwner(e => e.Order);
Konfiguracja związana z relacją między właścicielem i właścicielem powinna być teraz łańcuchowa po WithOwner()
podobnej do konfiguracji innych relacji.
Mimo że konfiguracja samego typu własności nadal będzie łańcuchowa po OwnsOne()/OwnsMany()
.
Na przykład:
modelBuilder.Entity<Order>.OwnsOne(e => e.Details, eb =>
{
eb.WithOwner()
.HasForeignKey(e => e.AlternateId)
.HasConstraintName("FK_OrderDetails");
eb.ToTable("OrderDetails");
eb.HasKey(e => e.AlternateId);
eb.HasIndex(e => e.Id);
eb.HasOne(e => e.Customer).WithOne();
eb.HasData(
new OrderDetails
{
AlternateId = 1,
Id = -1
});
});
Ponadto wywołanie Entity()
metody , HasOne()
lub Set()
z obiektem docelowym typu należącego do firmy spowoduje teraz zgłoszenie wyjątku.
Dlaczego
Ta zmiana została wprowadzona w celu utworzenia czystszego rozdzielenia między skonfigurowaniem samego typu własności a relacją z typem własności.
To z kolei eliminuje niejednoznaczność i zamieszanie wokół metod takich jak HasForeignKey
.
Środki zaradcze
Zmień konfigurację relacji typu własności, aby używać nowej powierzchni interfejsu API, jak pokazano w powyższym przykładzie.
Jednostki zależne udostępniające tabelę jednostce nadrzędnej są teraz opcjonalne
Stare zachowanie
Rozważ następujący model :
public class Order
{
public int Id { get; set; }
public int CustomerId { get; set; }
public OrderDetails Details { get; set; }
}
public class OrderDetails
{
public int Id { get; set; }
public string ShippingAddress { get; set; }
}
Przed programem EF Core 3.0, jeśli OrderDetails
jest własnością Order
lub jawnie zamapowany na tę samą tabelę OrderDetails
, wystąpienie zawsze było wymagane podczas dodawania nowego Order
elementu .
Nowe zachowanie
Począwszy od wersji 3.0, program EF Core umożliwia dodanie Order
elementu bez elementu OrderDetails
i mapowania wszystkich OrderDetails
właściwości z wyjątkiem klucza podstawowego do kolumn dopuszczanych do wartości null.
Podczas wykonywania zapytań względem zestawów OrderDetails
null
EF Core, jeśli którakolwiek z jej wymaganych właściwości nie ma wartości lub jeśli nie ma wymaganych właściwości oprócz klucza podstawowego, a wszystkie właściwości to null
.
Środki zaradcze
Jeśli model ma współużytkowanie tabeli zależne od wszystkich kolumn opcjonalnych, ale nawigacja wskazująca ją nie powinna być null
zgodna z oczekiwaniami, należy zmodyfikować aplikację tak, aby obsługiwała przypadki, gdy nawigacja to null
. Jeśli nie jest to możliwe, wymagana właściwość powinna zostać dodana do typu jednostki lub co najmniej jedna właściwość powinna mieć przypisaną wartość innąnull
niż.
Wszystkie jednostki udostępniające tabelę z kolumną tokenu współbieżności muszą mapować ją na właściwość
Problem ze śledzeniem nr 14154
Stare zachowanie
Rozważ następujący model :
public class Order
{
public int Id { get; set; }
public int CustomerId { get; set; }
public byte[] Version { get; set; }
public OrderDetails Details { get; set; }
}
public class OrderDetails
{
public int Id { get; set; }
public string ShippingAddress { get; set; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Order>()
.Property(o => o.Version).IsRowVersion().HasColumnName("Version");
}
Przed programem EF Core 3.0, jeśli OrderDetails
jest własnością Order
lub jawnie zamapowany na tę samą tabelę, aktualizacja tylko OrderDetails
nie Version
zaktualizuje wartości na kliencie, a następna aktualizacja zakończy się niepowodzeniem.
Nowe zachowanie
Począwszy od wersji 3.0, program EF Core propaguje nową Version
wartość, jeśli Order
jest właścicielem OrderDetails
. W przeciwnym razie podczas walidacji modelu jest zgłaszany wyjątek.
Dlaczego
Ta zmiana została wprowadzona, aby uniknąć nieaktualnej wartości tokenu współbieżności, gdy zostanie zaktualizowana tylko jedna z jednostek zamapowanych na tę samą tabelę.
Środki zaradcze
Wszystkie jednostki współużytujące tabelę muszą zawierać właściwość zamapowana na kolumnę tokenu współbieżności. Istnieje możliwość utworzenia jednego w stanie cienia:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<OrderDetails>()
.Property<byte[]>("Version").IsRowVersion().HasColumnName("Version");
}
Nie można wykonywać zapytań dotyczących jednostek należących do właściciela bez użycia zapytania śledzenia
Problem ze śledzeniem nr 18876
Stare zachowanie
Przed programem EF Core 3.0 można odpytować należące do nich jednostki jako inne nawigacje.
context.People.Select(p => p.Address);
Nowe zachowanie
Począwszy od wersji 3.0, program EF Core zgłosi zgłoszenie, jeśli śledzenie projektów zapytań jest własnością jednostki bez właściciela.
Dlaczego
Nie można manipulować należącymi jednostkami bez właściciela, więc w zdecydowanej większości przypadków wykonywanie zapytań względem nich w ten sposób jest błędem.
Środki zaradcze
Jeśli jednostka będąca własnością powinna być modyfikowana w jakikolwiek sposób później, właściciel powinien zostać uwzględniony w zapytaniu.
W przeciwnym razie dodaj wywołanie AsNoTracking()
:
context.People.Select(p => p.Address).AsNoTracking();
Właściwości dziedziczone z niemapowanych typów są teraz mapowane na jedną kolumnę dla wszystkich typów pochodnych
Problem ze śledzeniem nr 13998
Stare zachowanie
Rozważ następujący model :
public abstract class EntityBase
{
public int Id { get; set; }
}
public abstract class OrderBase : EntityBase
{
public int ShippingAddress { get; set; }
}
public class BulkOrder : OrderBase
{
}
public class Order : OrderBase
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Ignore<OrderBase>();
modelBuilder.Entity<EntityBase>();
modelBuilder.Entity<BulkOrder>();
modelBuilder.Entity<Order>();
}
Przed programem EF Core 3.0 ShippingAddress
właściwość zostanie zamapowana na oddzielne kolumny i BulkOrder
Order
domyślnie.
Nowe zachowanie
Począwszy od wersji 3.0, program EF Core tworzy tylko jedną kolumnę dla programu ShippingAddress
.
Dlaczego
Stare zachowanie było nieoczekiwane.
Środki zaradcze
Właściwość nadal może być jawnie mapowana na oddzielną kolumnę dla typów pochodnych:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Ignore<OrderBase>();
modelBuilder.Entity<EntityBase>();
modelBuilder.Entity<BulkOrder>()
.Property(o => o.ShippingAddress).HasColumnName("BulkShippingAddress");
modelBuilder.Entity<Order>()
.Property(o => o.ShippingAddress).HasColumnName("ShippingAddress");
}
Konwencja właściwości klucza obcego nie jest już zgodna z tą samą nazwą co właściwość główna
Problem ze śledzeniem nr 13274
Stare zachowanie
Rozważ następujący model :
public class Customer
{
public int CustomerId { get; set; }
public ICollection<Order> Orders { get; set; }
}
public class Order
{
public int Id { get; set; }
public int CustomerId { get; set; }
}
Przed programem EF Core 3.0 CustomerId
właściwość będzie używana dla klucza obcego zgodnie z konwencją.
Jeśli jednak jest typem należącym do Order
użytkownika, będzie to również CustomerId
klucz podstawowy i zwykle nie jest to oczekiwane.
Nowe zachowanie
Począwszy od wersji 3.0, program EF Core nie próbuje używać właściwości dla kluczy obcych zgodnie z konwencją, jeśli mają taką samą nazwę jak właściwość główna. Główna nazwa typu połączona z główną nazwą właściwości, a nazwa nawigacji połączona z głównymi wzorcami nazw właściwości są nadal zgodne. Na przykład:
public class Customer
{
public int Id { get; set; }
public ICollection<Order> Orders { get; set; }
}
public class Order
{
public int Id { get; set; }
public int CustomerId { get; set; }
}
public class Customer
{
public int Id { get; set; }
public ICollection<Order> Orders { get; set; }
}
public class Order
{
public int Id { get; set; }
public int BuyerId { get; set; }
public Customer Buyer { get; set; }
}
Dlaczego
Ta zmiana została wprowadzona, aby uniknąć błędnego zdefiniowania właściwości klucza podstawowego dla typu należącego do użytkownika.
Środki zaradcze
Jeśli właściwość miała być kluczem obcym, a tym samym częścią klucza podstawowego, jawnie skonfiguruj ją jako taką.
Połączenie z bazą danych jest teraz zamykane, jeśli nie jest już używane przed ukończeniem transakcjiScope
Problem ze śledzeniem nr 14218
Stare zachowanie
Przed programem EF Core 3.0, jeśli kontekst otwiera połączenie wewnątrz TransactionScope
, połączenie pozostaje otwarte, gdy bieżący TransactionScope
jest aktywny.
using (new TransactionScope())
{
using (AdventureWorks context = new AdventureWorks())
{
context.ProductCategories.Add(new ProductCategory());
context.SaveChanges();
// Old behavior: Connection is still open at this point
var categories = context.ProductCategories().ToList();
}
}
Nowe zachowanie
Począwszy od wersji 3.0, program EF Core zamyka połączenie natychmiast po zakończeniu korzystania z niego.
Dlaczego
Ta zmiana umożliwia używanie wielu kontekstów w tym samym TransactionScope
pliku . Nowe zachowanie jest również zgodne z platformą EF6.
Środki zaradcze
Jeśli połączenie musi pozostać otwarte jawne wywołanie OpenConnection()
, zapewni, że program EF Core nie zamknie go przedwcześnie:
using (new TransactionScope())
{
using (AdventureWorks context = new AdventureWorks())
{
context.Database.OpenConnection();
context.ProductCategories.Add(new ProductCategory());
context.SaveChanges();
var categories = context.ProductCategories().ToList();
context.Database.CloseConnection();
}
}
Każda właściwość używa niezależnej generacji klucza całkowitego w pamięci
Stare zachowanie
Przed programem EF Core 3.0 jeden udostępniony generator wartości był używany dla wszystkich właściwości klucza całkowitego w pamięci.
Nowe zachowanie
Począwszy od programu EF Core 3.0, każda właściwość klucza całkowitego pobiera własny generator wartości podczas korzystania z bazy danych w pamięci. Ponadto jeśli baza danych zostanie usunięta, generowanie klucza zostanie zresetowane dla wszystkich tabel.
Dlaczego
Ta zmiana została wprowadzona w celu dokładniejszego dopasowania generowania klucza w pamięci do rzeczywistego generowania kluczy bazy danych i zwiększenia możliwości odizolowania testów od siebie podczas korzystania z bazy danych w pamięci.
Środki zaradcze
Może to uszkodzić aplikację, która opiera się na określonych wartościach klucza w pamięci, które mają zostać ustawione. Zamiast tego nie należy polegać na określonych wartościach klucza lub aktualizowaniu, aby dopasować je do nowego zachowania.
Pola kopii zapasowej są używane domyślnie
Problem ze śledzeniem nr 12430
Stare zachowanie
Przed 3.0, nawet jeśli pole zapasowe dla właściwości było znane, program EF Core nadal będzie domyślnie odczytywać i zapisywać wartość właściwości przy użyciu metody pobierania właściwości i ustawiania. Wyjątkiem było wykonanie zapytania, w którym pole tworzenia kopii zapasowej zostałoby ustawione bezpośrednio, jeśli jest znane.
Nowe zachowanie
Począwszy od programu EF Core 3.0, jeśli pole zapasowe właściwości jest znane, program EF Core będzie zawsze odczytywał i zapisywał te właściwości przy użyciu pola zapasowego. Może to spowodować przerwanie działania aplikacji, jeśli aplikacja korzysta z dodatkowego zachowania zakodowanego w metodach getter lub setter.
Dlaczego
Ta zmiana została wprowadzona w celu uniemożliwienia programowi EF Core błędnego wyzwalania logiki biznesowej domyślnie podczas wykonywania operacji bazy danych obejmujących jednostki.
Środki zaradcze
Zachowanie przed 3.0 można przywrócić za pomocą konfiguracji trybu dostępu do właściwości w systemie ModelBuilder
.
Na przykład:
modelBuilder.UsePropertyAccessMode(PropertyAccessMode.PreferFieldDuringConstruction);
Zgłaszaj, czy znaleziono wiele zgodnych pól kopii zapasowych
Problem ze śledzeniem nr 12523
Stare zachowanie
Przed programem EF Core 3.0, jeśli wiele pól pasuje do reguł znajdowania pola zapasowego właściwości, jedno pole zostanie wybrane na podstawie pewnej kolejności pierwszeństwa. Może to spowodować, że niewłaściwe pole będzie używane w niejednoznacznych przypadkach.
Nowe zachowanie
Począwszy od programu EF Core 3.0, jeśli wiele pól jest dopasowanych do tej samej właściwości, zgłaszany jest wyjątek.
Dlaczego
Ta zmiana została wprowadzona, aby uniknąć dyskretnego używania jednego pola w innym, gdy tylko jedno pole może być poprawne.
Środki zaradcze
Właściwości z niejednoznacznymi polami zapasowymi muszą mieć pole do jawnego użycia. Na przykład przy użyciu płynnego interfejsu API:
modelBuilder
.Entity<Blog>()
.Property(e => e.Id)
.HasField("_id");
Nazwy właściwości tylko dla pól powinny być zgodne z nazwą pola
Stare zachowanie
Przed programem EF Core 3.0 właściwość może być określona przez wartość ciągu i jeśli nie znaleziono właściwości o tej nazwie na typie platformy .NET, program EF Core spróbuje dopasować ją do pola przy użyciu reguł konwencji.
private class Blog
{
private int _id;
public string Name { get; set; }
}
modelBuilder
.Entity<Blog>()
.Property("Id");
Nowe zachowanie
Począwszy od programu EF Core 3.0, właściwość tylko dla pola musi być dokładnie zgodna z nazwą pola.
modelBuilder
.Entity<Blog>()
.Property("_id");
Dlaczego
Ta zmiana została wprowadzona, aby uniknąć używania tego samego pola dla dwóch właściwości o podobnej nazwie. Powoduje to również, że zgodne reguły właściwości tylko dla pól są takie same jak właściwości mapowane na właściwości CLR.
Środki zaradcze
Właściwości tylko pola muszą mieć taką samą nazwę jak pole, do którego są mapowane. W przyszłej wersji programu EF Core po wersji 3.0 planujemy ponowne włączenie jawnego konfigurowania nazwy pola, która różni się od nazwy właściwości (zobacz problem nr 15307):
modelBuilder
.Entity<Blog>()
.Property("Id")
.HasField("_id");
AddDbContext/AddDbContextPool nie wywołuje już funkcji AddLogging i AddMemoryCache
Problem ze śledzeniem nr 14756
Stare zachowanie
Przed programem EF Core 3.0 wywoływanie AddDbContext
lub AddDbContextPool
rejestrowanie usług rejestrowania i buforowania pamięci przy użyciu di za pomocą wywołań AddLogging i AddMemoryCache.
Nowe zachowanie
Począwszy od programu EF Core 3.0 i AddDbContext
AddDbContextPool
nie zarejestruje już tych usług za pomocą wstrzykiwania zależności (DI).
Dlaczego
Program EF Core 3.0 nie wymaga, aby te usługi były w kontenerze DI aplikacji. Jeśli ILoggerFactory
jednak jest zarejestrowany w kontenerze di aplikacji, będzie on nadal używany przez program EF Core.
Środki zaradcze
Jeśli aplikacja potrzebuje tych usług, zarejestruj je jawnie w kontenerze DI przy użyciu polecenia AddLogging lub AddMemoryCache.
AddEntityFramework* dodaje funkcję IMemoryCache z limitem rozmiaru
Problem ze śledzeniem nr 12905
Stare zachowanie
Przed programem EF Core 3.0 metody wywołujące AddEntityFramework*
będą również rejestrować usługi buforowania pamięci z di bez limitu rozmiaru.
Nowe zachowanie
Począwszy od programu EF Core 3.0, AddEntityFramework*
zarejestruje usługę IMemoryCache z limitem rozmiaru. Jeśli inne usługi dodane później zależą od usługi IMemoryCache, mogą szybko osiągnąć domyślny limit powodujący wyjątki lub obniżoną wydajność.
Dlaczego
Użycie usługi IMemoryCache bez limitu może spowodować niekontrolowane użycie pamięci, jeśli w logice buforowania zapytań występuje usterka lub zapytania są generowane dynamicznie. Posiadanie domyślnego limitu ogranicza potencjalny atak DoS.
Środki zaradcze
W większości przypadków wywoływanie wywołania AddEntityFramework*
nie jest konieczne, jeśli AddDbContext
wywołana jest również funkcja lub AddDbContextPool
. W związku z tym najlepszym ograniczeniem jest usunięcie wywołania AddEntityFramework*
.
Jeśli aplikacja wymaga tych usług, zarejestruj implementację IMemoryCache jawnie z kontenerem DI wcześniej przy użyciu funkcji AddMemoryCache.
Funkcja DbContext.Entry wykonuje teraz lokalną funkcję DetectChanges
Problem ze śledzeniem nr 13552
Stare zachowanie
Przed programem EF Core 3.0 wywołanie spowoduje wykrycie DbContext.Entry
zmian dla wszystkich śledzonych jednostek.
Dzięki temu stan uwidoczniony w obiekcie EntityEntry
był aktualny.
Nowe zachowanie
Począwszy od programu EF Core 3.0, wywołanie DbContext.Entry
spowoduje teraz tylko próbę wykrycia zmian w danej jednostce i wszelkich śledzonych podmiotów zabezpieczeń powiązanych z nią.
Oznacza to, że zmiany w innym miejscu mogły nie zostać wykryte przez wywołanie tej metody, co może mieć wpływ na stan aplikacji.
Należy pamiętać, że jeśli ChangeTracker.AutoDetectChangesEnabled
jest ustawiona na false
wartość , nawet to lokalne wykrywanie zmian zostanie wyłączone.
Inne metody, które powodują wykrywanie zmian — na przykład ChangeTracker.Entries
i SaveChanges
— nadal powodują pełne DetectChanges
wszystkie śledzone jednostki.
Dlaczego
Ta zmiana została wprowadzona w celu zwiększenia domyślnej wydajności korzystania z programu context.Entry
.
Środki zaradcze
Wywołaj ChangeTracker.DetectChanges()
jawnie przed wywołaniem metody Entry
, aby upewnić się, że zachowanie przed 3.0.
Klucze ciągów i tablic bajtów nie są domyślnie generowane przez klienta
Problem ze śledzeniem nr 14617
Stare zachowanie
Przed programem EF Core 3.0 string
i byte[]
właściwościami klucza można użyć bez jawnego ustawienia wartości innej niż null.
W takim przypadku wartość klucza zostanie wygenerowana na kliencie jako identyfikator GUID, serializowany do bajtów dla elementu byte[]
.
Nowe zachowanie
Począwszy od programu EF Core 3.0 zostanie zgłoszony wyjątek wskazujący, że nie ustawiono żadnej wartości klucza.
Dlaczego
Ta zmiana została wprowadzona, ponieważ wartości generowane string
/byte[]
przez klienta zazwyczaj nie są przydatne, a domyślne zachowanie utrudniało wnioskowanie o wygenerowanych wartościach kluczy w typowy sposób.
Środki zaradcze
Zachowanie przed 3.0 można uzyskać przez jawne określenie, że właściwości klucza powinny używać wygenerowanych wartości, jeśli nie ustawiono żadnej innej wartości innej niż null. Na przykład za pomocą płynnego interfejsu API:
modelBuilder
.Entity<Blog>()
.Property(e => e.Id)
.ValueGeneratedOnAdd();
Lub z adnotacjami danych:
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string Id { get; set; }
ILoggerFactory jest teraz usługą o określonym zakresie
Problem ze śledzeniem nr 14698
Stare zachowanie
Przed programem EF Core 3.0 ILoggerFactory
została zarejestrowana jako pojedyncza usługa.
Nowe zachowanie
Począwszy od programu EF Core 3.0, ILoggerFactory
jest teraz zarejestrowany jako zakres.
Dlaczego
Ta zmiana została wprowadzona w celu umożliwienia skojarzenia rejestratora z wystąpieniem DbContext
, które umożliwia korzystanie z innych funkcji i usuwa niektóre przypadki patologicznego zachowania, takiego jak eksplozja wewnętrznych dostawców usług.
Środki zaradcze
Ta zmiana nie powinna mieć wpływu na kod aplikacji, chyba że rejestruje i korzysta z usług niestandardowych u wewnętrznego dostawcy usług EF Core.
To nie jest typowe.
W takich przypadkach większość rzeczy będzie nadal działać, ale każda pojedyncza usługa, która była zależna od ILoggerFactory
, musi zostać zmieniona, aby uzyskać element ILoggerFactory
w inny sposób.
Jeśli wystąpią takie sytuacje, zgłoś problem w monitorze problemów platformy EF Core w usłudze GitHub, aby poinformować nas, jak używasz ILoggerFactory
takiego rozwiązania, abyśmy mogli lepiej zrozumieć, jak nie przerywać tego ponownie w przyszłości.
Serwery proxy ładowania z opóźnieniem nie zakładają już, że właściwości nawigacji są w pełni ładowane
Problem ze śledzeniem nr 12780
Stare zachowanie
Przed ef Core 3.0, gdy DbContext
obiekt został usunięty, nie było możliwości poznania, czy dana właściwość nawigacji na jednostce uzyskanej z tego kontekstu została w pełni załadowana, czy nie.
Zamiast tego serwery proxy zakładają, że nawigacja referencyjna jest ładowana, jeśli ma wartość inną niż null, i że nawigacja kolekcji jest ładowana, jeśli nie jest pusta.
W takich przypadkach próba leniwego ładowania byłaby no-op.
Nowe zachowanie
Począwszy od programu EF Core 3.0, serwery proxy śledzą, czy właściwość nawigacji jest ładowana. Oznacza to, że próba uzyskania dostępu do właściwości nawigacji ładowanej po usunięciu kontekstu zawsze będzie bezoperacyjna, nawet jeśli załadowana nawigacja jest pusta lub ma wartość null. Z drugiej strony próba uzyskania dostępu do właściwości nawigacji, która nie jest załadowana, zgłosi wyjątek, jeśli kontekst zostanie usunięty, nawet jeśli właściwość nawigacji jest niepustą kolekcją. Jeśli wystąpi taka sytuacja, oznacza to, że kod aplikacji próbuje użyć ładowania leniwego w nieprawidłowym czasie, a aplikacja powinna zostać zmieniona, aby tego nie robić.
Dlaczego
Ta zmiana została wprowadzona, aby zachowanie było spójne i poprawne podczas próby opóźnionego ładowania w usuniętym DbContext
wystąpieniu.
Środki zaradcze
Zaktualizuj kod aplikacji, aby nie próbował ładować z opóźnieniem z usuniętym kontekstem lub skonfigurować go tak, aby był no-op zgodnie z opisem w komunikacie o wyjątku.
Nadmierne tworzenie wewnętrznych dostawców usług jest teraz domyślnie błędem
Problem ze śledzeniem nr 10236
Stare zachowanie
Przed programem EF Core 3.0 zostanie zarejestrowane ostrzeżenie dla aplikacji tworzącej patologiczną liczbę dostawców usług wewnętrznych.
Nowe zachowanie
Począwszy od programu EF Core 3.0, to ostrzeżenie jest teraz uznawane za błąd i zgłaszany jest wyjątek.
Dlaczego
Ta zmiana została wprowadzona w celu zwiększenia kodu aplikacji poprzez bardziej jawne ujawnienie tego patologicznego przypadku.
Środki zaradcze
Najbardziej odpowiednią przyczyną działania w przypadku napotkania tego błędu jest zrozumienie głównej przyczyny i zaprzestanie tworzenia tak wielu wewnętrznych dostawców usług.
Jednak błąd można przekonwertować z powrotem na ostrzeżenie (lub zignorowane) za pomocą konfiguracji w pliku DbContextOptionsBuilder
.
Na przykład:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.ConfigureWarnings(w => w.Log(CoreEventId.ManyServiceProvidersCreatedWarning));
}
Nowe zachowanie funkcji HasOne/HasMany o nazwie z jednym ciągiem
Stare zachowanie
Przed programem EF Core 3.0 wywołanie HasOne
kodu lub HasMany
za pomocą jednego ciągu zostało zinterpretowane w mylący sposób.
Na przykład:
modelBuilder.Entity<Samurai>().HasOne("Entrance").WithOne();
Kod wygląda tak, jakby odnosił Samurai
się do innego typu jednostki przy użyciu Entrance
właściwości nawigacji, która może być prywatna.
W rzeczywistości ten kod próbuje utworzyć relację z typem jednostki o nazwie Entrance
bez właściwości nawigacji.
Nowe zachowanie
Począwszy od programu EF Core 3.0, powyższy kod teraz robi to, jak wyglądało to wcześniej.
Dlaczego
Stare zachowanie było bardzo mylące, zwłaszcza podczas odczytywania kodu konfiguracji i wyszukiwania błędów.
Środki zaradcze
Spowoduje to przerwanie tylko aplikacji, które jawnie konfigurują relacje przy użyciu ciągów dla nazw typów i bez jawnego określenia właściwości nawigacji.
Nie jest to powszechne.
Poprzednie zachowanie można uzyskać za pośrednictwem jawnego przekazywania null
nazwy właściwości nawigacji.
Na przykład:
modelBuilder.Entity<Samurai>().HasOne("Some.Entity.Type.Name", null).WithOne();
Typ zwracany dla kilku metod asynchronicznych został zmieniony z Task na ValueTask
Problem ze śledzeniem nr 15184
Stare zachowanie
Następujące metody asynchroniczne zwróciły wcześniej element Task<T>
:
DbContext.FindAsync()
DbSet.FindAsync()
DbContext.AddAsync()
DbSet.AddAsync()
ValueGenerator.NextValueAsync()
(i klasy wyprowadzające)
Nowe zachowanie
Wyżej wymienione metody zwracają ValueTask<T>
teraz wartość w taki sam T
sposób jak poprzednio.
Dlaczego
Ta zmiana zmniejsza liczbę alokacji sterty poniesionej podczas wywoływania tych metod, zwiększając ogólną wydajność.
Środki zaradcze
Aplikacje oczekujące tylko na powyższe interfejsy API muszą zostać ponownie skompilowane — żadne zmiany źródła nie są konieczne.
Bardziej złożone użycie (np. przekazanie zwróconego elementu Task
do Task.WhenAny()
elementu ) zwykle wymaga przekonwertowania zwróconego elementu ValueTask<T>
na obiekt Task<T>
przez wywołanie AsTask()
metody .
Należy pamiętać, że spowoduje to negację redukcji alokacji, którą wprowadza ta zmiana.
Adnotacja Relational:TypeMapping jest teraz po prostu TypeMapping
Stare zachowanie
Nazwa adnotacji dla adnotacji mapowania typów to "Relational:TypeMapping".
Nowe zachowanie
Nazwa adnotacji dla adnotacji mapowania typów to teraz "TypeMapping".
Dlaczego
Mapowania typów są teraz używane dla nie tylko dostawców relacyjnych baz danych.
Środki zaradcze
Spowoduje to przerwanie tylko aplikacji, które uzyskują dostęp do mapowania typów bezpośrednio jako adnotacja, co nie jest typowe. Najbardziej odpowiednią akcją do naprawienia jest użycie powierzchni interfejsu API do uzyskiwania dostępu do mapowań typów zamiast bezpośredniego używania adnotacji.
Tabela ToTable w typie pochodnym zgłasza wyjątek
Problem ze śledzeniem nr 11811
Stare zachowanie
Przed programem EF Core 3.0 wywołanie typu pochodnego zostanie zignorowane, ponieważ tylko strategia mapowania dziedziczenia była TPH, ToTable()
gdy nie jest to prawidłowe.
Nowe zachowanie
Począwszy od programu EF Core 3.0 i w ramach przygotowań do dodawania obsługi TPT i TPC w nowszej wersji, wywołany typ pochodny zgłosi teraz wyjątek, ToTable()
aby uniknąć nieoczekiwanej zmiany mapowania w przyszłości.
Dlaczego
Obecnie nie jest prawidłowe mapowanie typu pochodnego na inną tabelę. Ta zmiana pozwala uniknąć przerwania w przyszłości, gdy stanie się prawidłową rzeczą do zrobienia.
Środki zaradcze
Usuń wszelkie próby mapowania typów pochodnych na inne tabele.
Element ForSqlServerHasIndex został zastąpiony hasindex
Problem ze śledzeniem nr 12366
Stare zachowanie
Przed programem EF Core 3.0 ForSqlServerHasIndex().ForSqlServerInclude()
udostępniono sposób konfigurowania kolumn używanych z INCLUDE
programem .
Nowe zachowanie
Począwszy od programu EF Core 3.0, korzystanie z Include
indeksu jest teraz obsługiwane na poziomie relacyjnym.
Użyj witryny HasIndex().ForSqlServerInclude()
.
Dlaczego
Ta zmiana została wprowadzona w celu skonsolidowania interfejsu API dla indeksów Include
z jednym miejscem dla wszystkich dostawców baz danych.
Środki zaradcze
Użyj nowego interfejsu API, jak pokazano powyżej.
Zmiany interfejsu API metadanych
Nowe zachowanie
Następujące właściwości zostały przekonwertowane na metody rozszerzenia:
IEntityType.QueryFilter
->GetQueryFilter()
IEntityType.DefiningQuery
->GetDefiningQuery()
IProperty.IsShadowProperty
->IsShadowProperty()
IProperty.BeforeSaveBehavior
->GetBeforeSaveBehavior()
IProperty.AfterSaveBehavior
->GetAfterSaveBehavior()
Dlaczego
Ta zmiana upraszcza implementację wyżej wymienionych interfejsów.
Środki zaradcze
Użyj nowych metod rozszerzenia.
Zmiany interfejsu API metadanych specyficzne dla dostawcy
Nowe zachowanie
Metody rozszerzenia specyficzne dla dostawcy zostaną spłaszczone:
IProperty.Relational().ColumnName
->IProperty.GetColumnName()
IEntityType.SqlServer().IsMemoryOptimized
->IEntityType.IsMemoryOptimized()
PropertyBuilder.UseSqlServerIdentityColumn()
->PropertyBuilder.UseIdentityColumn()
Dlaczego
Ta zmiana upraszcza implementację wyżej wymienionych metod rozszerzeń.
Środki zaradcze
Użyj nowych metod rozszerzenia.
Program EF Core nie wysyła już pragma dla wymuszania klucza FK SQLite
Problem ze śledzeniem nr 12151
Stare zachowanie
Przed programem EF Core 3.0 program EF Core będzie wysyłał PRAGMA foreign_keys = 1
po otwarciu połączenia z sqlite.
Nowe zachowanie
Począwszy od programu EF Core 3.0, program EF Core nie jest PRAGMA foreign_keys = 1
już wysyłany po otwarciu połączenia z sqlite.
Dlaczego
Ta zmiana została wprowadzona, ponieważ program EF Core używa SQLitePCLRaw.bundle_e_sqlite3
domyślnie, co z kolei oznacza, że wymuszanie szyfrowania FK jest domyślnie włączone i nie musi być jawnie włączone za każdym razem, gdy połączenie jest otwarte.
Środki zaradcze
Klucze obce są domyślnie włączone w SQLitePCLRaw.bundle_e_sqlite3, która jest domyślnie używana dla platformy EF Core.
W innych przypadkach klucze obce można włączyć, określając Foreign Keys=True
w parametry połączenia.
Microsoft.EntityFrameworkCore.Sqlite teraz zależy od SQLitePCLRaw.bundle_e_sqlite3
Stare zachowanie
Przed programem EF Core 3.0 używany był program SQLitePCLRaw.bundle_green
EF Core.
Nowe zachowanie
Począwszy od programu EF Core 3.0, program EF Core używa programu SQLitePCLRaw.bundle_e_sqlite3
.
Dlaczego
Ta zmiana została wprowadzona tak, aby wersja sqLite używana w systemie iOS była zgodna z innymi platformami.
Środki zaradcze
Aby użyć natywnej wersji SQLite w systemie iOS, skonfiguruj opcję Microsoft.Data.Sqlite
korzystania z innego SQLitePCLRaw
pakietu.
Wartości guid są teraz przechowywane jako TEKST w sqlite
Problem ze śledzeniem nr 15078
Stare zachowanie
Wartości identyfikatora GUID były wcześniej przechowywane jako wartości obiektów BLOB w sqlite.
Nowe zachowanie
Wartości identyfikatora GUID są teraz przechowywane jako TEXT.
Dlaczego
Format binarny identyfikatorów GUID nie jest ustandaryzowany. Przechowywanie wartości w formacie TEXT sprawia, że baza danych jest bardziej zgodna z innymi technologiami.
Środki zaradcze
Istniejące bazy danych można migrować do nowego formatu, wykonując polecenie SQL w następujący sposób.
UPDATE MyTable
SET GuidColumn = hex(substr(GuidColumn, 4, 1)) ||
hex(substr(GuidColumn, 3, 1)) ||
hex(substr(GuidColumn, 2, 1)) ||
hex(substr(GuidColumn, 1, 1)) || '-' ||
hex(substr(GuidColumn, 6, 1)) ||
hex(substr(GuidColumn, 5, 1)) || '-' ||
hex(substr(GuidColumn, 8, 1)) ||
hex(substr(GuidColumn, 7, 1)) || '-' ||
hex(substr(GuidColumn, 9, 2)) || '-' ||
hex(substr(GuidColumn, 11, 6))
WHERE typeof(GuidColumn) == 'blob';
W programie EF Core można również kontynuować korzystanie z poprzedniego zachowania, konfigurując konwerter wartości dla tych właściwości.
modelBuilder
.Entity<MyEntity>()
.Property(e => e.GuidProperty)
.HasConversion(
g => g.ToByteArray(),
b => new Guid(b));
Microsoft.Data.Sqlite może odczytywać wartości guid zarówno z kolumn BLOB, jak i TEXT; jednak ponieważ domyślny format parametrów i stałych uległ zmianie, prawdopodobnie trzeba będzie podjąć działania w przypadku większości scenariuszy obejmujących identyfikatory GUID.
Wartości znaków są teraz przechowywane jako TEKST w sqlite
Problem ze śledzeniem nr 15020
Stare zachowanie
Wartości char były wcześniej przechowywane jako wartości INTEGER w sqlite. Na przykład wartość char A została zapisana jako wartość całkowita 65.
Nowe zachowanie
Wartości znaków są teraz przechowywane jako TEKST.
Dlaczego
Przechowywanie wartości jako tekstu jest bardziej naturalne i sprawia, że baza danych jest bardziej zgodna z innymi technologiami.
Środki zaradcze
Istniejące bazy danych można migrować do nowego formatu, wykonując polecenie SQL w następujący sposób.
UPDATE MyTable
SET CharColumn = char(CharColumn)
WHERE typeof(CharColumn) = 'integer';
W programie EF Core można również kontynuować korzystanie z poprzedniego zachowania, konfigurując konwerter wartości dla tych właściwości.
modelBuilder
.Entity<MyEntity>()
.Property(e => e.CharProperty)
.HasConversion(
c => (long)c,
i => (char)i);
Microsoft.Data.Sqlite może również odczytywać wartości znaków zarówno z kolumn INTEGER, jak i TEXT, więc niektóre scenariusze mogą nie wymagać żadnej akcji.
Identyfikatory migracji są teraz generowane przy użyciu niezmiennego kalendarza kultury
Problem ze śledzeniem nr 12978
Stare zachowanie
Identyfikatory migracji zostały przypadkowo wygenerowane przy użyciu kalendarza bieżącej kultury.
Nowe zachowanie
Identyfikatory migracji są teraz zawsze generowane przy użyciu niezmiennego kalendarza kultury (Gregorian).
Dlaczego
Kolejność migracji jest ważna podczas aktualizowania bazy danych lub rozwiązywania konfliktów scalania. Użycie niezmiennego kalendarza pozwala uniknąć problemów z porządkowaniami, które mogą wynikać z tego, że członkowie zespołu mają różne kalendarze systemowe.
Środki zaradcze
Ta zmiana dotyczy każdego, kto korzysta z kalendarza innego niż gregoriański, w którym rok jest większy niż kalendarz gregoriański (taki jak tajski kalendarz buddyjski). Istniejące identyfikatory migracji należy zaktualizować, aby nowe migracje były uporządkowane po istniejących migracjach.
Identyfikator migracji można znaleźć w atrybucie Migracja w plikach projektanta migracji.
[DbContext(typeof(MyDbContext))]
-[Migration("25620318122820_MyMigration")]
+[Migration("20190318122820_MyMigration")]
partial class MyMigration
{
Należy również zaktualizować tabelę Historii migracji.
UPDATE __EFMigrationsHistory
SET MigrationId = CONCAT(LEFT(MigrationId, 4) - 543, SUBSTRING(MigrationId, 4, 150))
Polecenie UseRowNumberForPaging zostało usunięte
Problem ze śledzeniem nr 16400
Stare zachowanie
Przed programem EF Core 3.0 UseRowNumberForPaging
można użyć do wygenerowania bazy danych SQL na potrzeby stronicowania zgodnego z programem SQL Server 2008.
Nowe zachowanie
Począwszy od programu EF Core 3.0, program EF wygeneruje tylko program SQL na potrzeby stronicowania, który jest zgodny tylko z nowszymi wersjami programu SQL Server.
Dlaczego
Wprowadzamy tę zmianę, ponieważ program SQL Server 2008 nie jest już obsługiwanym produktem i aktualizacja tej funkcji w celu pracy ze zmianami zapytań wprowadzonych w programie EF Core 3.0 jest znacząca.
Środki zaradcze
Zalecamy zaktualizowanie do nowszej wersji programu SQL Server lub użycie wyższego poziomu zgodności, aby wygenerowany program SQL był obsługiwany. Oznacza to, że jeśli nie możesz tego zrobić, skomentuj problem ze śledzeniem ze szczegółami. Możemy ponownie podjąć tę decyzję na podstawie opinii.
Informacje/metadane rozszerzenia zostały usunięte z rozszerzenia IDbContextOptionsExtension
Problem ze śledzeniem nr 16119
Stare zachowanie
IDbContextOptionsExtension
zawarte metody dostarczania metadanych dotyczących rozszerzenia.
Nowe zachowanie
Metody te zostały przeniesione do nowej DbContextOptionsExtensionInfo
abstrakcyjnej klasy bazowej, która jest zwracana z nowej IDbContextOptionsExtension.Info
właściwości.
Dlaczego
W wersjach z wersji 2.0 do 3.0 musieliśmy kilka razy dodać lub zmienić te metody. Podzielenie ich na nową abstrakcyjną klasę bazową ułatwi wprowadzanie tych zmian bez przerywania istniejących rozszerzeń.
Środki zaradcze
Zaktualizuj rozszerzenia, aby postępować zgodnie z nowym wzorcem.
Przykłady można znaleźć w wielu implementacjach IDbContextOptionsExtension
dla różnych rodzajów rozszerzeń w kodzie źródłowym platformy EF Core.
Nazwa elementu LogQueryPossibleExceptionWithAggregateOperator została zmieniona
Problem ze śledzeniem nr 10985
Zmień
RelationalEventId.LogQueryPossibleExceptionWithAggregateOperator
zmieniono nazwę na RelationalEventId.LogQueryPossibleExceptionWithAggregateOperatorWarning
.
Dlaczego
Wyrównuje nazewnictwo tego zdarzenia ostrzegawczego ze wszystkimi innymi zdarzeniami ostrzegawczymi.
Środki zaradcze
Użyj nowej nazwy. (Należy pamiętać, że numer identyfikatora zdarzenia nie został zmieniony).
Wyjaśnienie interfejsu API dla nazw ograniczeń klucza obcego
Problem ze śledzeniem nr 10730
Stare zachowanie
Przed programem EF Core 3.0 nazwy ograniczeń klucza obcego były nazywane po prostu "nazwą". Na przykład:
var constraintName = myForeignKey.Name;
Nowe zachowanie
Począwszy od programu EF Core 3.0, nazwy ograniczeń klucza obcego są teraz określane jako "nazwa ograniczenia". Na przykład:
var constraintName = myForeignKey.ConstraintName;
Dlaczego
Ta zmiana zapewnia spójność nazewnictwa w tym obszarze, a także wyjaśnia, że jest to nazwa ograniczenia klucza obcego, a nie nazwa kolumny lub właściwości zdefiniowanej przez klucz obcy.
Środki zaradcze
Użyj nowej nazwy.
IRelationalDatabaseCreator.HasTables/HasTablesAsync zostały upublicznione
Problem ze śledzeniem nr 15997
Stare zachowanie
Przed programem EF Core 3.0 te metody były chronione.
Nowe zachowanie
Począwszy od programu EF Core 3.0, te metody są publiczne.
Dlaczego
Te metody są używane przez program EF do określenia, czy baza danych jest tworzona, ale pusta. Może to być również przydatne spoza ef podczas określania, czy należy zastosować migracje.
Środki zaradcze
Zmień dostępność wszelkich przesłonięć.
Microsoft.EntityFrameworkCore.Design jest teraz pakietem DevelopmentDependency
Problem ze śledzeniem nr 11506
Stare zachowanie
Przed programem EF Core 3.0 Microsoft.EntityFrameworkCore.Design był zwykłym pakietem NuGet, którego zestaw może być przywoływane przez projekty, które od niego zależą.
Nowe zachowanie
Począwszy od programu EF Core 3.0, jest to pakiet DevelopmentDependency. Oznacza to, że zależność nie będzie przepływać przechodnio do innych projektów i że domyślnie nie można odwoływać się do jej zestawu.
Dlaczego
Ten pakiet ma być używany tylko w czasie projektowania. Wdrożone aplikacje nie powinny się do niego odwoływać. Utworzenie pakietu jako elementu DevelopmentDependency wzmacnia to zalecenie.
Środki zaradcze
Jeśli chcesz odwołać się do tego pakietu, aby zastąpić zachowanie czasu projektowania platformy EF Core, możesz zaktualizować metadane elementu PackageReference w projekcie.
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.0.0">
<PrivateAssets>all</PrivateAssets>
<!-- Remove IncludeAssets to allow compiling against the assembly -->
<!--<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>-->
</PackageReference>
Jeśli pakiet jest przywoływany przechodnio za pośrednictwem narzędzia Microsoft.EntityFrameworkCore.Tools, należy dodać jawny element PackageReference do pakietu, aby zmienić jego metadane. Takie jawne odwołanie należy dodać do dowolnego projektu, w którym potrzebne są typy z pakietu.
SQLitePCL.raw zaktualizowano do wersji 2.0.0
Problem ze śledzeniem nr 14824
Stare zachowanie
Microsoft.EntityFrameworkCore.Sqlite wcześniej zależało od wersji 1.1.12 SQLitePCL.raw.
Nowe zachowanie
Zaktualizowaliśmy nasz pakiet tak, aby był zależny od wersji 2.0.0.
Dlaczego
Wersja 2.0.0 SQLitePCL.raw jest przeznaczona dla platformy .NET Standard 2.0. Wcześniej była przeznaczona dla platformy .NET Standard 1.1, która wymagała dużego zamknięcia pakietów przechodnich do pracy.
Środki zaradcze
SQLitePCL.raw w wersji 2.0.0 zawiera pewne zmiany powodujące niezgodność. Aby uzyskać szczegółowe informacje, zobacz informacje o wersji.
NetTopologySuite zaktualizowano do wersji 2.0.0
Problem ze śledzeniem nr 14825
Stare zachowanie
Pakiety przestrzenne były wcześniej zależne od wersji 1.15.1 aplikacji NetTopologySuite.
Nowe zachowanie
Zaktualizowaliśmy nasz pakiet, aby był zależny od wersji 2.0.0.
Dlaczego
Wersja 2.0.0 aplikacji NetTopologySuite ma na celu rozwiązanie kilku problemów z użytecznością napotykanych przez użytkowników platformy EF Core.
Środki zaradcze
NetTopologySuite w wersji 2.0.0 zawiera pewne zmiany powodujące niezgodność. Aby uzyskać szczegółowe informacje, zobacz informacje o wersji.
Element Microsoft.Data.SqlClient jest używany zamiast Elementu System.Data.SqlClient
Problem ze śledzeniem nr 15636
Stare zachowanie
Microsoft.EntityFrameworkCore.SqlServer wcześniej zależało od elementu System.Data.SqlClient.
Nowe zachowanie
Zaktualizowaliśmy nasz pakiet, aby zależeć od elementu Microsoft.Data.SqlClient.
Dlaczego
Microsoft.Data.SqlClient jest flagowym sterownikiem dostępu do danych dla programu SQL Server w przyszłości, a program System.Data.SqlClient nie jest już przedmiotem programowania. Niektóre ważne funkcje, takie jak Always Encrypted, są dostępne tylko w programie Microsoft.Data.SqlClient.
Środki zaradcze
Jeśli kod przyjmuje bezpośrednią zależność od elementu System.Data.SqlClient, należy zmienić go tak, aby odwołył się do elementu Microsoft.Data.SqlClient; ponieważ te dwa pakiety zachowują bardzo wysoki stopień zgodności interfejsu API, powinno to być tylko prosta zmiana pakietu i przestrzeni nazw.
Należy skonfigurować wiele niejednoznacznych relacji odwołujących się do siebie
Problem ze śledzeniem nr 13573
Stare zachowanie
Typ jednostki z wieloma własnymi odwołaniami do właściwości nawigacji jednokierunkowej i dopasowywania zestawów FKs został niepoprawnie skonfigurowany jako pojedyncza relacja. Na przykład:
public class User
{
public Guid Id { get; set; }
public User CreatedBy { get; set; }
public User UpdatedBy { get; set; }
public Guid CreatedById { get; set; }
public Guid? UpdatedById { get; set; }
}
Nowe zachowanie
Ten scenariusz jest teraz wykrywany w kompilowaniu modelu i zgłaszany jest wyjątek wskazujący, że model jest niejednoznaczny.
Dlaczego
Wynikowy model był niejednoznaczny i prawdopodobnie będzie prawdopodobnie nieprawidłowy w tym przypadku.
Środki zaradcze
Użyj pełnej konfiguracji relacji. Na przykład:
modelBuilder
.Entity<User>()
.HasOne(e => e.CreatedBy)
.WithMany();
modelBuilder
.Entity<User>()
.HasOne(e => e.UpdatedBy)
.WithMany();
Parametr DbFunction.Schema jest pusty lub ma wartość null, konfiguruje go tak, aby był w domyślnym schemacie modelu
Problem ze śledzeniem nr 12757
Stare zachowanie
Funkcja DbFunction skonfigurowana ze schematem jako pusty ciąg była traktowana jako funkcja wbudowana bez schematu. Na przykład poniższy kod zamapuje DatePart
funkcję CLR na DATEPART
wbudowaną funkcję na serwerze SqlServer.
[DbFunction("DATEPART", Schema = "")]
public static int? DatePart(string datePartArg, DateTime? date) => throw new Exception();
Nowe zachowanie
Wszystkie mapowania DbFunction są uważane za mapowane na funkcje zdefiniowane przez użytkownika. W związku z tym pusta wartość ciągu spowoduje umieszczenie funkcji wewnątrz domyślnego schematu modelu. Może to być schemat skonfigurowany jawnie za pośrednictwem płynnego interfejsu API modelBuilder.HasDefaultSchema()
lub dbo
w inny sposób.
Dlaczego
Wcześniej schemat był pustym sposobem traktowania tej funkcji jest wbudowany, ale ta logika ma zastosowanie tylko dla programu SqlServer, gdzie wbudowane funkcje nie należą do żadnego schematu.
Środki zaradcze
Ręczne konfigurowanie tłumaczenia dbFunction w celu zamapowania go na wbudowaną funkcję.
modelBuilder
.HasDbFunction(typeof(MyContext).GetMethod(nameof(MyContext.DatePart)))
.HasTranslation(args => SqlFunctionExpression.Create("DatePart", args, typeof(int?), null));
Program EF Core 3.0 jest przeznaczony dla platformy .NET Standard 2.1, a nie .NET Standard 2.0 Przywrócono
Problem ze śledzeniem nr 15498
Program EF Core 3.0 jest przeznaczony dla platformy .NET Standard 2.1, co jest zmianą powodującą niezgodność, która wyklucza aplikacje .NET Framework. Program EF Core 3.1 przywrócił ten element i ponownie jest przeznaczony dla platformy .NET Standard 2.0.
Wykonywanie zapytania jest rejestrowane na poziomie debugowania Przywrócono
Problem ze śledzeniem nr 14523
Przywróciliśmy tę zmianę, ponieważ nowa konfiguracja w programie EF Core 3.0 umożliwia określenie przez aplikację poziomu dziennika dla dowolnego zdarzenia. Aby na przykład przełączyć rejestrowanie bazy danych SQL na Debug
, jawnie skonfiguruj poziom w OnConfiguring
systemie lub AddDbContext
:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseSqlServer(connectionString)
.ConfigureWarnings(c => c.Log((RelationalEventId.CommandExecuting, LogLevel.Debug)));