EF Core 5.0 での破壊的変更Breaking changes in EF Core 5.0

次の API と動作の変更により、EF Core 5.0.0 に更新されている既存のアプリケーションが破損する可能性があります。The following API and behavior changes have the potential to break existing applications updating to EF Core 5.0.0.

まとめSummary

重大な変更Breaking change 影響Impact
プリンシパルへのナビゲーションと依存関係へのナビゲーションでは、Required のセマンティクスが異なりますRequired on the navigation from principal to dependent has different semantics 中間Medium
クエリの定義は、プロバイダー固有のメソッドに置き換えられますDefining query is replaced with provider-specific methods 中間Medium
SQLite NTS 拡張機能から HasGeometricDimension メソッドが削除されましたRemoved HasGeometricDimension method from SQLite NTS extension LowLow
Cosmos: パーティション キーが主キーに追加されるようになりましたCosmos: Partition key is now added to the primary key Low
Cosmos: id プロパティの名前が __id に変更されましたCosmos: id property renamed to __id Low
Cosmos: byte[] が、数値配列ではなく base64 文字列として格納されるようになりましたCosmos: byte[] is now stored as a base64 string instead of a number array Low
Cosmos: GetPropertyName と SetPropertyName の名前が変更されましたCosmos: GetPropertyName and SetPropertyName were renamed Low
エンティティの状態が Detached から Unchanged、Updated、または Deleted に変更されると、値ジェネレーターが呼び出されますValue generators are called when the entity state is changed from Detached to Unchanged, Updated, or Deleted Low
IMigrationsModelDiffer で IRelationalModel が使用されるようになりましたIMigrationsModelDiffer now uses IRelationalModel Low
識別子が読み取り専用ですDiscriminators are read-only LowLow

SQLite NTS 拡張機能から HasGeometricDimension メソッドが削除されましたRemoved HasGeometricDimension method from SQLite NTS extension

イシュー #14257 の追跡Tracking Issue #14257

以前の動作Old behavior

HasGeometricDimension は、geometry 列で追加のディメンション (Z および M) を有効にするために使用されていました。HasGeometricDimension was used to enable additional dimensions (Z and M) on geometry columns. ただし、この影響を受けていたのはデータベースの作成だけです。However, it only ever affected database creation. 追加のディメンションで値をクエリするためにそれを指定する必要はありませんでした。It was unnecessary to specify it to query values with additional dimensions. また、追加のディメンションで値を挿入または更新するときもそれは正しく機能しませんでした (#14257 を参照してください)。It also didn't work correctly when inserting or updating values with additional dimensions (see #14257).

新しい動作New behavior

追加のディメンション (Z および M) で geometry 値の挿入と更新を有効にするには、列の型名の一部としてディメンションを指定する必要があります。To enable inserting and updating geometry values with additional dimensions (Z and M), the dimension needs to be specified as part of the column type name. この API は、SpatiaLite の AddGeometryColumn 関数の基になる動作により厳密に一致します。This API matches more closely to the underlying behavior of SpatiaLite's AddGeometryColumn function.

理由Why

列の型でディメンションを指定した後に HasGeometricDimension を使用することは不要であり冗長なので、HasGeometricDimension を完全に削除しました。Using HasGeometricDimension after specifying the dimension in the column type is unnecessary and redundant, so we removed HasGeometricDimension entirely.

軽減策Mitigations

HasColumnType を使用してディメンションを指定します。Use HasColumnType to specify the dimension:

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");
    });

プリンシパルへのナビゲーションと依存関係へのナビゲーションでは、Required のセマンティクスが異なりますRequired on the navigation from principal to dependent has different semantics

問題 #17286 の追跡Tracking Issue #17286

以前の動作Old behavior

必要に応じて、プリンシパルへのナビゲーションのみを構成できます。Only the navigations to principal could be configured as required. したがって、依存関係 (外部キーを含むエンティティ) へのナビゲーションで RequiredAttribute を使用すると、定義エンティティ型上に外部キーが作成されます。Therefore using RequiredAttribute on the navigation to the dependent (the entity containing the foreign key) would instead create the foreign key on the defining entity type.

新しい動作New behavior

必要な依存関係に対するサポートが追加されたため、必要に応じて任意の参照ナビゲーションをマークできるようになりました。つまり、上記の例では、外部キーはリレーションシップのもう一方の側で定義され、プロパティは必須としてマークされません。With the added support for required dependents, it is now possible to mark any reference navigation as required, meaning that in the case shown above the foreign key will be defined on the other side of the relationship and the properties won't be marked as required.

依存関係の終了を指定する前の IsRequired の呼び出しがあいまいになりました。Calling IsRequired before specifying the dependent end is now ambiguous:

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

理由Why

必要な依存関係のサポートを有効にするために、新しい動作が必要です (#12100 を参照)。The new behavior is necessary to enable support for required dependents (see #12100).

軽減策Mitigations

依存関係へのナビゲーションから RequiredAttribute を削除し、代わりにプリンシパルへのナビゲーションに配置するか、または OnModelCreating でリレーションシップを構成します。Remove RequiredAttribute from the navigation to the dependent and place it instead on the navigation to the principal or configure the relationship in OnModelCreating:

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

Cosmos: パーティション キーが主キーに追加されるようになりましたCosmos: Partition key is now added to the primary key

問題 #15289 の追跡Tracking Issue #15289

以前の動作Old behavior

パーティション キー プロパティは、id を含む代替キーにのみ追加されました。The partition key property was only added to the alternate key that includes id.

新しい動作New behavior

規則に従って、パーティション キー プロパティも主キーに追加されるようになりました。The partition key property is now also added to the primary key by convention.

理由Why

この変更により、モデルと Azure Cosmos DB セマンティクスとの連携が向上し、Find と一部のクエリのパフォーマンスが向上します。This change makes the model better aligned with Azure Cosmos DB semantics and improves the performance of Find and some queries.

軽減策Mitigations

パーティション キー プロパティを主キーに追加しないようにするには、OnModelCreating で構成します。To prevent the partition key property to be added to the primary key, configure it in OnModelCreating.

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

Cosmos: id プロパティの名前が __id に変更されましたCosmos: id property renamed to __id

問題 #17751 の追跡Tracking Issue #17751

以前の動作Old behavior

id JSON プロパティにマップされたシャドウ プロパティも id に名前変更されました。The shadow property mapped to the id JSON property was also named id.

新しい動作New behavior

規則に従って作成されたシャドウ プロパティは __id という名前になりました。The shadow property created by convention is now named __id.

理由Why

この変更により、id プロパティがエンティティ型の既存のプロパティと競合する可能性が低くなります。This change makes it less likely that the id property clashes with an existing property on the entity type.

軽減策Mitigations

3.x の動作に戻るには、OnModelCreatingid プロパティを構成します。To go back to the 3.x behavior, configure the id property in OnModelCreating.

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

Cosmos: byte[] が、数値配列ではなく base64 文字列として格納されるようになりましたCosmos: byte[] is now stored as a base64 string instead of a number array

問題 #17306 の追跡Tracking Issue #17306

以前の動作Old behavior

byte[] 型のプロパティは、数値配列として格納されていました。Properties of type byte[] were stored as a number array.

新しい動作New behavior

byte[] 型のプロパティは、base64 文字列として格納されるようになりました。Properties of type byte[] are now stored as a base64 string.

理由Why

この byte[] の表現は期待に沿ったもので、主要な JSON シリアル化ライブラリの既定の動作です。This representation of byte[] aligns better with expectations and is the default behavior of the major JSON serialization libraries.

軽減策Mitigations

数値配列として格納されている既存のデータは、引き続き正しくクエリされますが、現在、挿入動作を元に戻す方法はサポートされていません。Existing data stored as number arrays will still be queried correctly, but currently there isn't a supported way to change back the insert behavior. この制限がシナリオの妨げとなっている場合は、この問題にコメントしてください。If this limitation is blocking your scenario, comment on this issue

Cosmos: GetPropertyName と SetPropertyName の名前が変更されましたCosmos: GetPropertyName and SetPropertyName were renamed

問題 #17874 の追跡Tracking Issue #17874

以前の動作Old behavior

以前は、拡張メソッドは、GetPropertyName および SetPropertyName と呼ばれていましたPreviously the extension methods were called GetPropertyName and SetPropertyName

新しい動作New behavior

古い API は廃止され、新しいメソッド GetJsonPropertyNameSetJsonPropertyName が追加されましたThe old API was obsoleted and new methods added: GetJsonPropertyName, SetJsonPropertyName

理由Why

この変更により、これらのメソッドの構成に関するあいまいさが解消されます。This change removes the ambiguity around what these methods are configuring.

軽減策Mitigations

新しい API を使用するか、古い警告を一時的に中断します。Use the new API or temporarily suspend the obsolete warnings.

エンティティの状態が Detached から Unchanged、Updated、または Deleted に変更されると、値ジェネレーターが呼び出されますValue generators are called when the entity state is changed from Detached to Unchanged, Updated, or Deleted

問題 #15289 の追跡Tracking Issue #15289

以前の動作Old behavior

値ジェネレーターは、エンティティの状態が Added に変更されたときにのみ呼び出されていました。Value generators were only called when the entity state changed to Added.

新しい動作New behavior

値ジェネレーターは、エンティティの状態が Detached から Unchanged、Updated、または Deleted に変更され、プロパティに既定値が含まれているときに呼び出されるようになりました。Value generators are now called when the entity state is changed from Detached to Unchanged, Updated, or Deleted and the property contains the default values.

理由Why

この変更は、データストアに保持されていない、常にクライアントで値が生成されるプロパティのエクスペリエンスを向上させるために必要でした。This change was necessary to improve the experience with properties that are not persisted to the data store and have their value generated always on the client.

軽減策Mitigations

値ジェネレーターが呼び出されないようにするには、状態が変わる前に、既定値以外の値をプロパティに割り当てます。To prevent the value generator from being called, assign a non-default value to the property before the state is changed.

IMigrationsModelDiffer で IRelationalModel が使用されるようになりましたIMigrationsModelDiffer now uses IRelationalModel

問題 #20305 の追跡Tracking Issue #20305

以前の動作Old behavior

IMigrationsModelDiffer API は IModel を使用して定義されていました。IMigrationsModelDiffer API was defined using IModel.

新しい動作New behavior

IMigrationsModelDiffer API で IRelationalModel が使用されるようになりました。IMigrationsModelDiffer API now uses IRelationalModel. ただし、IModel はアプリケーションの一部であり、より重大な変更を加えることなく Entity Framework でこれを変更することはできないため、モデル スナップショットには引き続きこのコードのみが含まれています。However the model snapshot still contains only IModel as this code is part of the application and Entity Framework can't change it without making a bigger breaking change.

理由Why

IRelationalModel は、データベース スキーマの新しく追加された表現です。IRelationalModel is a newly added representation of the database schema. 違いを見つけるためにこれを使用する方が高速で正確です。Using it to find differences is faster and more accurate.

軽減策Mitigations

次のコードを使用して、snapshot のモデルを context のモデルと比較します。Use the following code to compare the model from snapshot with the model from 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());

6.0 でこのエクスペリエンスを向上させることを計画しています (#22031 を参照)We are planning to improve this experience in 6.0 (see #22031)

識別子が読み取り専用ですDiscriminators are read-only

問題 #21154 の追跡Tracking Issue #21154

以前の動作Old behavior

SaveChanges を呼び出す前に識別子の値を変更することができました。It was possible to change the discriminator value before calling SaveChanges

新しい動作New behavior

上記のケースでは、例外がスローされます。An exception will be throws in the above case.

理由Why

EF では、追跡中のエンティティ型を変更することは想定されていません。したがって、識別子の値を変更するとコンテキストが不整合な状態になり、予期しない動作が発生する可能性があります。EF doesn't expect the entity type to change while it is still being tracked, so changing the discriminator value leaves the context in an inconsistent state, which might result in unexpected behavior.

軽減策Mitigations

識別子の値を変更する必要があり、SaveChanges を呼び出した直後にコンテキストが破棄される場合は、識別子を変更可能にすることができます。If changing the discriminator value is necessary and the context will be disposed immediately after calling SaveChanges, the discriminator can be made mutable:

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

クエリの定義は、プロバイダー固有のメソッドに置き換えられますDefining query is replaced with provider-specific methods

問題 #18903 の追跡Tracking Issue #18903

以前の動作Old behavior

エンティティ型は、コア レベルでクエリを定義するためにマップされました。Entity types were mapped to defining queries at the Core level. エンティティ型のクエリ ルートでエンティティ型が使用されたときはいつでも、任意のプロバイダーのクエリの定義に置き換えられました。Anytime the entity type was used in the query root of the entity type was replaced by the defining query for any provider.

新しい動作New behavior

クエリを定義するための API は非推奨とされます。APIs for defining query are deprecated. 新しいプロバイダー固有の API が導入されました。New provider-specific APIs were introduced.

理由Why

クエリでクエリ ルートが使用される場合は常に、クエリの定義が置換クエリとして実装されましたが、いくつかの問題がありました。While defining queries were implemented as replacement query whenever query root is used in the query, it had a few issues:

  • クエリの定義で Select メソッドの new { ... } を使用してエンティティ型を射影している場合、それをエンティティとして識別するには追加の作業が必要で、EF Core によりクエリで名目的な型が処理される方法と矛盾していました。If defining query is projecting entity type using new { ... } in Select method, then identifying that as an entity required additional work and made it inconsistent with how EF Core treats nominal types in the query.
  • リレーショナル プロバイダーの場合は、LINQ 式形式で SQL 文字列を渡すために FromSql が引き続き必要です。For relational providers FromSql is still needed to pass the SQL string in LINQ expression form.

最初に定義されたクエリは、キーなしエンティティ用のメモリ内プロバイダーで使用されるクライアント側のビュー (リレーショナル データベースのデータベース ビューに似ています) として導入されました。Initially defining queries were introduced as client-side views to be used with In-Memory provider for keyless entities (similar to database views in relational databases). このような定義により、メモリ内データベースに対してアプリケーションを簡単にテストできます。Such definition makes it easy to test application against in-memory database. その後、それらは広く適用できるようになりました。これは有用でしたが、一貫性がなく、動作を理解するのが困難でした。Afterwards they became broadly applicable, which was useful but brought inconsistent and hard to understand behavior. そのため、概念を簡略化することにしました。So we decided to simplify the concept. LINQ ベースのクエリをメモリ内プロバイダーに限定して定義し、異なる方法で処理しました。We made LINQ based defining query exclusive to In-Memory provider and treat them differently. 詳細については、この問題を参照してください。For more information, see this issue.

軽減策Mitigations

リレーショナル プロバイダーの場合は、OnModelCreatingToSqlQuery メソッドを使用し、エンティティ型に使用する SQL 文字列を渡します。For relational providers, use ToSqlQuery method in OnModelCreating and pass in a SQL string to use for the entity type. メモリ内プロバイダーの場合は、OnModelCreatingToInMemoryQuery メソッドを使用し、エンティティ型に使用する LINQ クエリを渡します。For the In-Memory provider, use ToInMemoryQuery method in OnModelCreating and pass in a LINQ query to use for the entity type.