Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Poniższa lista zawiera główne nowe funkcje w rozwiązaniu EF Core 3.x
Jako wersja główna, rozwiązanie EF Core 3.x zawiera również kilka zmian powodujących niezgodność, które są ulepszeniami interfejsu API mogącymi mieć negatywny wpływ na istniejące aplikacje.
Przebudowa składni LINQ
Składnia LINQ umożliwia pisanie zapytań do bazy danych przy użyciu samodzielnie wybranego języka platformy .NET, korzystając z rozbudowanych informacji o typie w celu oferowania funkcji IntelliSense i sprawdzania typów w czasie kompilacji. Jednak składnia LINQ umożliwia również pisanie nieograniczonej liczby skomplikowanych zapytań zawierających dowolne wyrażenia (wywołania metod lub operacje). Sposób obsługi wszystkich tych kombinacji jest głównym wyzwaniem dla dostawców LINQ.
W rozwiązaniu EF Core 3.x przebudowaliśmy naszego dostawcę LINQ, aby umożliwić tłumaczenie większej liczby wzorców zapytań na język SQL i generowanie wydajnych zapytań w większej liczbie przypadków oraz zapobiegać sytuacjom, w których nieefektywne zapytania pozostawały niewykryte. Nowy dostawca LINQ jest podstawą, na której będziemy mogli oferować nowe możliwości zapytań i ulepszenia wydajności w przyszłych wersjach bez zrywania zgodności z istniejącymi aplikacjami i dostawcami danych.
Ograniczone przetwarzanie po stronie klienta
Najważniejsza zmiana projektu ma związek ze sposobem obsługi wyrażeń LINQ, których nie można przekonwertować na parametry ani przetłumaczyć na język SQL.
W poprzednich wersjach rozwiązanie EF Core identyfikowało, jakie części zapytania można przetłumaczyć na język SQL, i wykonywało resztę zapytania na kliencie. Ten typ wykonywania po stronie klienta jest pożądany w niektórych sytuacjach, ale w wielu innych może to skutkować nieefektywnymi zapytaniami.
Jeśli na przykład rozwiązanie EF Core 2.2 nie mogło przetłumaczyć predykatu w wywołaniu Where()
, wykonywało instrukcję SQL bez filtru, transferowało wszystkie wiersze z bazy danych, a następnie filtrowało je w pamięci:
var specialCustomers = context.Customers
.Where(c => c.Name.StartsWith(n) && IsSpecialCustomer(c));
Może to być dopuszczalne, jeśli baza danych zawiera niewielką liczbę wierszy, ale może powodować znaczne problemy z wydajnością, a nawet awarię aplikacji, jeśli baza danych zawiera dużą liczbę wierszy.
W rozwiązaniu EF Core 3.x ograniczyliśmy przetwarzanie po stronie klienta tylko do projekcji najwyższego poziomu (zasadniczo ostatnie wywołanie metody Select()
).
Gdy rozwiązanie EF Core 3.x wykrywa w zapytaniu wyrażenia, których nie można przetłumaczyć w żaden sposób, zgłasza wyjątek środowiska uruchomieniowego.
Aby przetworzyć warunek predykatu na kliencie, jak w poprzednim przykładzie, deweloperzy muszą teraz jawnie przełączyć przetwarzanie zapytania na LINQ to Objects:
var specialCustomers = context.Customers
.Where(c => c.Name.StartsWith(n))
.AsEnumerable() // switches to LINQ to Objects
.Where(c => IsSpecialCustomer(c));
Zobacz dokumentację zmian powodujących niezgodność, aby uzyskać więcej informacji na temat tego, jak może to wpłynąć na istniejące aplikacje.
Pojedyncza instrukcja SQL na zapytanie LINQ
Innym aspektem projektu, który zmienił się znacząco w wersji 3.x, jest to, że teraz zawsze generujemy pojedynczą instrukcję SQL na zapytanie LINQ. W poprzednich wersjach w niektórych przypadkach generowaliśmy wiele instrukcji SQL, tłumaczyliśmy wywołania metody Include()
dotyczące właściwości nawigacji kolekcji i tłumaczyliśmy zapytania, które podążały za pewnymi wzorcami z podzapytaniami. Chociaż w niektórych przypadkach było to wygodne, a w przypadku metody Include()
nawet pomagało unikać wysyłania nadmiarowych danych przez sieć, implementacja była złożona i skutkowała bardzo nieefektywnym działaniem (N+1 zapytań). Występowały sytuacje, w których dane zwracane z różnych zapytań były potencjalnie niespójne.
Podobnie jak w przypadku przetwarzania po stronie klienta, jeśli rozwiązanie EF Core 3.x nie może przetłumaczyć zapytania LINQ na pojedynczą instrukcję SQL, zgłasza wyjątek środowiska uruchomieniowego. Udało nam się jednak wyposażyć rozwiązanie EF Core w możliwość tłumaczenia wielu typowych wzorców, które wcześniej generowały wiele zapytań, w pojedyncze zapytanie, używając do tego instrukcji JOIN.
Obsługa usługi Azure Cosmos DB
Dostawca usługi Azure Cosmos DB dla platformy EF Core umożliwia deweloperom zapoznanie się z modelem programowania EF, aby łatwo kierować usługę Azure Cosmos DB jako bazę danych aplikacji. Celem jest uczynienie niektórych zalet usługi Azure Cosmos DB, takich jak dystrybucja globalna, dostępność "zawsze włączona", elastyczna skalowalność i małe opóźnienia, jeszcze bardziej dostępna dla deweloperów platformy .NET. Dostawca umożliwia korzystanie z większości funkcji platformy EF Core, takich jak automatyczne śledzenie zmian, konwersje LINQ i wartości w usłudze Azure Cosmos DB dla NoSQL.
Aby uzyskać więcej informacji, zobacz dokumentację dostawcy usługi Azure Cosmos DB.
Obsługa języka C# 8.0
Rozwiązanie EF Core 3.x korzysta z kilku nowych funkcji języka C# 8.0:
Asynchroniczne strumienie
Wyniki zapytania asynchronicznego są teraz udostępniane przy użyciu nowego standardowego interfejsu IAsyncEnumerable<T>
i mogą być używane przy użyciu instrukcji await foreach
.
var orders =
from o in context.Orders
where o.Status == OrderStatus.Pending
select o;
await foreach(var o in orders.AsAsyncEnumerable())
{
Process(o);
}
Aby uzyskać więcej informacji, zobacz strumienie asynchroniczne w dokumentacji języka C#.
Typy referencyjne dopuszczające wartość null
Po włączeniu tej nowej funkcji w kodzie rozwiązanie EF Core sprawdza nullowalność właściwości typu referencyjnego i stosuje ją do odpowiednich kolumn i relacji w bazie danych: właściwości nienullowalnych typów referencyjnych są traktowane tak, jakby miały atrybut adnotacji danych [Required]
.
Na przykład w następującej klasie właściwości oznaczone jako typ string?
zostaną skonfigurowane jako opcjonalne, natomiast string
zostaną skonfigurowane zgodnie z wymaganiami:
public class Customer
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string? MiddleName { get; set; }
}
Aby uzyskać więcej informacji, zobacz Praca z nullowalnymi typami referencyjnymi w dokumentacji rozwiązania EF Core.
Przechwytywanie operacji bazy danych
Nowy interfejs API przechwytywania w rozwiązaniu EF Core 3.x umożliwia dostarczanie niestandardowej logiki, która ma być automatycznie wywoływana przy każdym uruchomieniu operacji bazy danych niskiego poziomu w ramach normalnego działania rozwiązania EF Core. Przykładowo podczas otwierania połączeń, zatwierdzania transakcji, lub wykonywania poleceń.
Podobnie jak w przypadku funkcji przechwytywania, które istniały w rozwiązaniu EF 6, interceptory pozwalają przechwytywać operacje przed lub po ich wystąpieniu. Gdy przechwycisz je przed ich wystąpieniem, możesz pominąć wykonywanie i dostarczyć alternatywne wyniki z logiki przechwytywania.
Aby na przykład zmodyfikować tekst polecenia, możesz utworzyć klasę DbCommandInterceptor
:
public class HintCommandInterceptor : DbCommandInterceptor
{
public override InterceptionResult<DbDataReader> ReaderExecuting(
DbCommand command,
CommandEventData eventData,
InterceptionResult<DbDataReader> result)
{
// Manipulate the command text, etc. here...
command.CommandText += " OPTION (OPTIMIZE FOR UNKNOWN)";
return result;
}
}
I zarejestrować ją w klasie DbContext
:
services.AddDbContext(b => b
.UseSqlServer(connectionString)
.AddInterceptors(new HintCommandInterceptor()));
Inżynieria odwrotna widoków bazy danych
Typy zapytań, które reprezentują dane możliwe do odczytania z bazy danych, ale nie do zaktualizowania, zostały zmienione na bezkluczowe typy jednostek. Ponieważ doskonale nadają się do mapowania widoków baz danych w większości scenariuszy, rozwiązanie EF Core automatycznie tworzy bezkluczowe typy jednostek podczas inżynierii odwrotnej widoków baz danych.
Na przykład za pomocą narzędzia wiersza polecenia dotnet ef można wpisać:
dotnet ef dbcontext scaffold "Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer
Narzędzie będzie teraz automatycznie tworzyć szkielety typów dla widoków i tabel bez kluczy:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Names>(entity =>
{
entity.HasNoKey();
entity.ToView("Names");
});
modelBuilder.Entity<Things>(entity =>
{
entity.HasNoKey();
});
}
Jednostki zależne udostępniające tabelę jednostce nadrzędnej są teraz opcjonalne
Począwszy od rozwiązania EF Core 3.x, jeśli element OrderDetails
jest własnością elementu Order
lub jest jawnie zamapowany na tę samą tabelę, można dodać element Order
bez elementu OrderDetails
i wszystkie właściwości OrderDetails
, z wyjątkiem klucza podstawowego, zostaną zamapowane na nullowalne kolumny.
Podczas wykonywania zapytań rozwiązanie EF Core ustawia element OrderDetails
na wartość null
, jeśli którakolwiek z jego 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 są równe null
.
public class Order
{
public int Id { get; set; }
public int CustomerId { get; set; }
public OrderDetails Details { get; set; }
}
[Owned]
public class OrderDetails
{
public int Id { get; set; }
public string ShippingAddress { get; set; }
}
Rozwiązanie EF 6.3 na platformie .NET Core
Tak naprawdę nie jest to funkcja rozwiązania EF Core 3.x, ale uważamy, że jest to ważne dla wielu naszych obecnych klientów.
Rozumiemy, że wiele istniejących aplikacji korzysta z poprzednich wersji rozwiązania EF i że przenoszenie ich do rozwiązania EF Core tylko w celu skorzystania z platformy .NET Core może wymagać znacznego nakładu pracy. Z tego powodu postanowiliśmy przystosować najnowszą wersję rozwiązania EF 6 do działania na platformie .NET Core 3.x.
Aby uzyskać więcej informacji, zobacz, co nowego w rozwiązaniu EF 6.
Odroczone funkcje
Niektóre funkcje pierwotnie planowane dla rozwiązania EF Core 3.x zostały przełożone na przyszłe wersje: