Entity Framework Core 3.x の新機能New features in Entity Framework Core 3.x

以下のリストには、EF Core 3.x の主な新機能が含まれていますThe following list includes the major new features in EF Core 3.x

メジャー リリースである EF Core 3.x には、いくつかの破壊的変更も含まれています。これは、既存のアプリケーションに悪影響を及ぼす可能性がある API の強化です。As a major release, EF Core 3.x also contains several breaking changes, which are API improvements that may have negative impact on existing applications.

LINQ の見直しLINQ overhaul

LINQ を使うと、任意の .NET 言語を使ってデータベース クエリを記述でき、豊富な型情報を利用して IntelliSense とコンパイル時の型チェックを提供できます。LINQ enables you to write database queries using your .NET language of choice, taking advantage of rich type information to offer IntelliSense and compile-time type checking. しかし、LINQ では、任意の式 (メソッド呼び出しまたは操作) を含む複雑なクエリを無制限に記述できます。But LINQ also enables you to write an unlimited number of complicated queries containing arbitrary expressions (method calls or operations). これらの組み合わせをすべて処理する方法は、LINQ プロバイダーの主要な課題です。How to handle all those combinations is the main challenge for LINQ providers.

EF Core 3.x では、LINQ プロバイダーが再設計され、より多くのクエリ パターンの SQL への変換、より多くのケースでの効率的なクエリの生成、非効率的なクエリの未検出の防止が可能になりました。In EF Core 3.x, we rearchitected our LINQ provider to enable translating more query patterns into SQL, generating efficient queries in more cases, and preventing inefficient queries from going undetected. 新しい LINQ プロバイダーは、既存のアプリケーションやデータ プロバイダーを破壊することなく、今後のリリースで新しいクエリ機能やパフォーマンスの改善を提供できるようにするための基盤です。The new LINQ provider is the foundation over which we'll be able to offer new query capabilities and performance improvements in future releases, without breaking existing applications and data providers.

制限付きクライアント評価Restricted client evaluation

最も重要な設計上の変更点は、パラメーターに変換できない、または SQL に変換できない LINQ 式の処理方法に関するものです。The most important design change has to do with how we handle LINQ expressions that cannot be converted to parameters or translated to SQL.

以前のバージョンの EF Core では、SQL に変換できるクエリの部分を特定し、残りのクエリをクライアント上で実行していました。In previous versions, EF Core identified what portions of a query could be translated to SQL, and executed the rest of the query on the client. この種のクライアント側の実行は、状況によっては望ましい場合がありますが、その他の多くのケースでは非効率的なクエリが発生する場合があります。This type of client-side execution is desirable in some situations, but in many other cases it can result in inefficient queries.

たとえば、EF Core 2.2 では、Where() 呼び出し内で述語を変換できなかった場合、フィルターなしで SQL ステートメントが実行され、すべての行がデータベースから転送された後、メモリ内でフィルター処理されます。For example, if EF Core 2.2 couldn't translate a predicate in a Where() call, it executed an SQL statement without a filter, transferred all the rows from the database, and then filtered them in-memory:

var specialCustomers = context.Customers
    .Where(c => c.Name.StartsWith(n) && IsSpecialCustomer(c));

これは、データベースに少数の行しか含まれていない場合には許容できる可能性がありますが、データベースに多数の行が含まれている場合は、パフォーマンスに大きな問題が発生したり、アプリケーションに障害が発生したりする可能性があります。That may be acceptable if the database contains a small number of rows but can result in significant performance issues or even application failure if the database contains a large number of rows.

EF Core 3.x では、クライアント評価は最上位レベルのプロジェクション (基本的には Select() への最後の呼び出し) でのみ発生するように制限されました。In EF Core 3.x, we've restricted client evaluation to only happen on the top-level projection (essentially, the last call to Select()). EF Core 3.x で、クエリ内の他の場所では変換できない式が検出された場合、ランタイム例外がスローされます。When EF Core 3.x detects expressions that can't be translated anywhere else in the query, it throws a runtime exception.

前の例のように述語の条件をクライアント上で評価するには、開発者がクエリの評価を LINQ to Objects に明示的に切り替えることが必要になりました。To evaluate a predicate condition on the client as in the previous example, developers now need to explicitly switch evaluation of the query to LINQ to Objects:

var specialCustomers = context.Customers
    .Where(c => c.Name.StartsWith(n))
    .AsEnumerable() // switches to LINQ to Objects
    .Where(c => IsSpecialCustomer(c));

これが既存のアプリケーションに与える可能性がある影響について詳しくは、破壊的変更に関するドキュメントをご覧ください。See the breaking changes documentation for more details about how this can affect existing applications.

LINQ クエリごとに 1 つの SQL ステートメントSingle SQL statement per LINQ query

3.x で大幅に変更された設計のもう 1 つの側面は、LINQ クエリごとに常に 1 つの SQL ステートメントが生成されるようになったことです。Another aspect of the design that changed significantly in 3.x is that we now always generate a single SQL statement per LINQ query. 以前のバージョンでは、コレクション ナビゲーション プロパティで Include() 呼び出しを変換する場合や、サブクエリを含む特定のパターンに従ったクエリを変換する場合など、場合によっては複数の SQL ステートメントが生成されていました。In previous versions, we used to generate multiple SQL statements in certain cases, translated Include() calls on collection navigation properties and translated queries that followed certain patterns with subqueries. これが便利なケースもいくつかあり、Include() の場合はネットワーク経由での冗長データの送信を回避するのにも役立ちました。しかし、実装が複雑になり、いくつかの非常に非効率的な動作 (N+1 クエリ) が発生しました。Although this was in some cases convenient, and for Include() it even helped avoid sending redundant data over the wire, the implementation was complex, and it resulted in some extremely inefficient behaviors (N+1 queries). 複数のクエリ間で返されたデータに、矛盾が生じる可能性がある状況が発生しました。There were situations in which the data returned across multiple queries was potentially inconsistent.

クライアント評価と同様に、EF Core 3.x で LINQ クエリを 1 つの SQL ステートメントに変換できなかった場合は、ランタイム例外がスローされます。Similarly to client evaluation, if EF Core 3.x can't translate a LINQ query into a single SQL statement, it throws a runtime exception. ただし、EF Core では、以前は複数のクエリが生成されていた一般的なパターンの多くを、JOIN を使って 1 つのクエリに変換できるようになっています。But we made EF Core capable of translating many of the common patterns that used to generate multiple queries to a single query with JOINs.

Cosmos DB のサポートCosmos DB support

EF Core 用の Cosmos DB プロバイダーでは、EF のプログラミング モデルに慣れている開発者が、Azure Cosmos DB をアプリケーション データベースとして簡単にターゲット設定できるようにします。The Cosmos DB provider for EF Core enables developers familiar with the EF programing model to easily target Azure Cosmos DB as an application database. その目的は、グローバル配布、"常にオン" 機能、高いスケーラビリティ、低待機時間など、Cosmos DB の利点のいくつかを .NET 開発者がさらに使いやすくすることです。The goal is to make some of the advantages of Cosmos DB, like global distribution, "always on" availability, elastic scalability, and low latency, even more accessible to .NET developers. プロバイダーでは、Cosmos DB の SQL API に対して、変更の自動追跡、LINQ、値変換など、ほとんどの EF Core 機能が有効になります。The provider enables most EF Core features, like automatic change tracking, LINQ, and value conversions, against the SQL API in Cosmos DB.

詳細については、Cosmos DB プロバイダーに関するドキュメントをご覧ください。See the Cosmos DB provider documentation for more details.

C# 8.0 のサポートC# 8.0 support

EF Core 3.x では、次のいくつかの C# 8.0 の新機能が利用されています。EF Core 3.x takes advantage of a couple of the new features in C# 8.0:

非同期ストリームAsynchronous streams

非同期クエリの結果は、新しい標準 IAsyncEnumerable<T> インターフェイスを使用して公開されるようになり、await foreach を使用して使用できるようになりました。Asynchronous query results are now exposed using the new standard IAsyncEnumerable<T> interface and can be consumed using 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);
}

詳細については、C# の非同期ストリームに関するドキュメントをご覧ください。See the asynchronous streams in the C# documentation for more details.

null 許容参照型Nullable reference types

コード内でこの新しい機能を有効にした場合、EF Core によって参照型プロパティの null 値の許容が調べられ、データベース内の対応する列およびリレーションシップにそれが適用されます。null 非許容参照型のプロパティは、[Required] データ注釈属性が含まれているかのように処理されます。When this new feature is enabled in your code, EF Core examines the nullability of reference type properties and applies it to corresponding columns and relationships in the database: properties of non-nullable references types are treated as if they had the [Required] data annotation attribute.

たとえば、次のクラスでは、型 string? としてマークされたプロパティは省略可能として構成されますが、string は必須として構成されます。For example, in the following class, properties marked as of type string? will be configured as optional, whereas string will be configured as required:

public class Customer
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string? MiddleName { get; set; }
}

詳細については、EF Core ドキュメントの「null 許容参照型の使用」をご覧ください。See Working with nullable reference types in the EF Core documentation for more details.

データベース操作のインターセプトInterception of database operations

EF Core 3.x の新しいインターセプト API を使うと、EF Core の通常操作の一部として低レベルのデータベース操作が発生するたびに、カスタム ロジックの提供が自動的に呼び出されるようにすることができます。The new interception API in EF Core 3.x allows providing custom logic to be invoked automatically whenever low-level database operations occur as part of the normal operation of EF Core. たとえば、接続を開いたり、トランザクションをコミットしたり、コマンドを実行したりする場合です。For example, when opening connections, committing transactions, or executing commands.

EF 6 に存在していたインターセプト機能と同様に、インターセプターによって、操作の発生前または発生後にそれをインターセプトすることができます。Similarly to the interception features that existed in EF 6, interceptors allow you to intercept operations before or after they happen. 操作の発生前にインターセプトした場合は、実行を回避し、インターセプトのロジックから代わりの結果を渡すことができます。When you intercept them before they happen, you are allowed to by-pass execution and supply alternate results from the interception logic.

たとえば、コマンド テキストを操作するために、DbCommandInterceptor を作成することができます。For example, to manipulate command text, you can create a 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;
    }
}

次に、 DbContext にこれを登録します。And register it with your DbContext:

services.AddDbContext(b => b
    .UseSqlServer(connectionString)
    .AddInterceptors(new HintCommandInterceptor()));

データベース ビューのリバース エンジニアリングReverse engineering of database views

クエリ型 (データベースから読み取ることはできても更新は行えないデータを表す) は、キーなしエンティティ型に名前が変更されました。Query types, which represent data that can be read from the database but not updated, have been renamed to keyless entity types. それはほとんどのシナリオでデータベース ビューのマッピングに対して最適であるため、データベース ビューのリバース エンジニアリングを行う場合に、EF Core によってキーなしエンティティ型が自動的に作成されるようになりました。As they are an excellent fit for mapping database views in most scenarios, EF Core now automatically creates keyless entity types when reverse engineering database views.

たとえば、dotnet ef コマンドライン ツールを使って次のように入力します。For example, using the dotnet ef command-line tool you can type:

dotnet ef dbcontext scaffold "Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer

すると、ツールによって、キーなしのビューとテーブルの型が自動的にスキャフォールディングされます。And the tool will now automatically scaffold types for views and tables without keys:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Names>(entity =>
    {
        entity.HasNoKey();
        entity.ToView("Names");
    });

    modelBuilder.Entity<Things>(entity =>
    {
        entity.HasNoKey();
    });
}

プリンシパルとテーブルを共有する依存エンティティが省略可能になりましたDependent entities sharing the table with the principal are now optional

EF Core 3.x 以降では、OrderDetailsOrder によって所有されている場合、または同じテーブルに明示的にマップされている場合、OrderDetails なしで Order を追加することができるようになり、主キー以外のすべての OrderDetails プロパティは NULL 値が許可される列にマップされます。Starting with EF Core 3.x, if OrderDetails is owned by Order or explicitly mapped to the same table, it will be possible to add an Order without an OrderDetails and all of the OrderDetails properties, except the primary key will be mapped to nullable columns.

クエリ時には、必須プロパティのいずれかに値がない場合、または主キー以外に必須プロパティがなく、すべてのプロパティが null である場合、EF Core によって OrderDetailsnull に設定されます。When querying, EF Core will set OrderDetails to null if any of its required properties doesn't have a value, or if it has no required properties besides the primary key and all properties are 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; }
}

.NET Core での EF 6.3EF 6.3 on .NET Core

これは EF Core 3.x の機能ではありませんが、現在のお客様の多くにとって重要であると考えられます。This isn't really an EF Core 3.x feature, but we think it is important to many of our current customers.

多くの既存のアプリケーションでは以前のバージョンの EF が使われていて、.NET Core を利用するためだけにそれらを EF Core に移植すると、多大な労力が必要となる場合があります。We understand that many existing applications use previous versions of EF, and that porting them to EF Core only to take advantage of .NET Core can require a significant effort. そのため、.NET Core 3.x 上で実行できるように最新バージョンの EF 6 を移植することに決定しました。For that reason, we decided to port the newest version of EF 6 to run on .NET Core 3.x.

詳細については、「EF 6 の新機能」をご覧ください。For more details, see what's new in EF 6.

延期された機能Postponed features

EF Core 3.x 向けに最初に計画された一部の機能は、今後のリリースに延期されました。Some features originally planned for EF Core 3.x were postponed to future releases:

  • 移行でモデルの一部を無視する機能。#2725 として追跡されています。Ability to ignore parts of a model in migrations, tracked as #2725.
  • プロパティ バッグのエンティティ。2 つの異なるイシューとして追跡されています: 共有型のエンティティに関する #9914 と、インデックス付きプロパティ マッピングのサポートに関する #13610Property bag entities, tracked as two separate issues: #9914 about shared-type entities and #13610 about indexed property mapping support.