このページでは、EF Core 10 から EF Core 11 に更新される既存のアプリケーションを中断する可能性がある API と動作の変更について説明します。 以前のバージョンの EF Core から更新する場合は、以前の破壊的変更を確認してください。
概要
注
Microsoft.Data.Sqlite を使用している場合は、後述の「Microsoft.Data.Sqlite の破壊的変更」についてのセクションをご覧ください。
影響が大きい変更
Cosmos: マップされていないプロパティが保持されなくなりました
以前の動作
以前は、EF Core が EF モデルにマップされていない JSON プロパティを含む Cosmos DB ドキュメントを読み取ると、これらの追加のプロパティは __jObject シャドウ プロパティに保持され、次の SaveChangesのデータベースに書き戻されていました。 ドキュメント内のマップされていないデータが透過的にラウンドトリップされました。
新しい動作
EF Core 11 以降では、Cosmos DB ドキュメントのマップされていない JSON プロパティは読み取り時に無視されます。 その後エンティティが保存されると、EF モデルに含まれていない追加のプロパティは失われます。
なぜでしょうか
__jObjectが削除されているため (「Cosmos: __jObject シャドウ プロパティの削除」を参照してください)。JObject はシリアル化に使用されなくなりました)。マップされていないプロパティを保持するメカニズムはありません。 EF Core 11 では、モデルから認識されるプロパティのみを処理するリーン JSON リーダーが使用されます。
緩和 策
アプリケーションがマップされていないデータの保持に依存している場合は、次のいずれかのオプションを検討してください。
- JSON 図形を完全に制御する必要があるドキュメントには、
CosmosClientを直接使用します。 - EF モデルで関連するすべてのプロパティを明示的にマップします。これには、保持する必要がある追加のフィールドも含まれます。
影響が中程度の変更
Azure Cosmos DB プロバイダー経由の同期 I/O が完全に削除されました
以前の動作
AZURE COSMOS DB プロバイダー経由の同期 I/O は、EF 9.0 (note) 以降サポートされていません。特別なオプトインが構成されていない限り、ToList や SaveChanges などの同期 I/O API を呼び出すと例外がスローされました。 オプトインが構成されている場合、同期 I/O API は以前と同様に機能し、プロバイダーは Azure Cosmos DB SDK に対して "sync-over-async" ブロックを実行するため、デッドロックやその他のパフォーマンスの問題が発生する可能性があります。
新しい動作
EF Core 11.0 以降では、同期 I/O API が呼び出されたときに EF が常にスローされるようになりました。 同期 I/O API の使用をオプトバックする方法はありません。
なぜでしょうか
非同期メソッド ("sync-over-async") での同期ブロックは非常に推奨されておらず、デッドロックやその他のパフォーマンスの問題につながる可能性があります。 Azure Cosmos DB SDK が非同期メソッドのみをサポートするため、EF Cosmos プロバイダーも非同期メソッドをサポートします。
緩和 策
同期 I/O API ではなく非同期 I/O API を使用するようにコードを変換します。 たとえば、 SaveChanges() の呼び出しを await SaveChangesAsync()に置き換えます。
Microsoft。Data.SqlClient が 7.0 に更新されました
以前の動作
EF Core 10 は Microsoft を使用します。Data.SqlClient 6.x。コア パッケージにAzure/Entra ID認証の依存関係 (Azure.Core、Azure.Identity、Microsoft.Identity.Client など) が含まれています。
新しい動作
EF Core 11 は、Microsoft に依存するようになりました。Data.SqlClient 7.0。 このバージョンでは、Azure/Entra ID (以前のAzure Active Directory) 認証の依存関係がコア パッケージから削除されます。 アプリケーションでEntra ID認証 (ActiveDirectoryDefault、ActiveDirectoryInteractive、ActiveDirectoryManagedIdentity、ActiveDirectoryServicePrincipal など) を使用する場合は、Microsoft.Data.SqlClient.Extensions.Azure パッケージを個別にインストールする必要があります。
さらに、 SqlAuthenticationMethod.ActiveDirectoryPassword は古いものとしてマークされています。
詳細については、Microsoftを参照してください。Data.SqlClient 7.0 リリース ノート。
なぜでしょうか
この変更は、Microsoft で行われました。Data.SqlClient:Azure認証を使用しないアプリケーションの依存関係の肥大化を軽減します。これは、コンテナー化されたデプロイやローカル開発に特に役立ちます。
緩和 策
アプリケーションで SQL Server でのEntra ID認証を使用する場合は、プロジェクトの Microsoft.Data.SqlClient.Extensions.Azure パッケージへの参照を追加します。
<PackageReference Include="Microsoft.Data.SqlClient.Extensions.Azure" Version="7.0.0" />
このパッケージ参照を追加する以外にコードを変更する必要はありません。
SqlAuthenticationMethod.ActiveDirectoryPasswordを使用する場合は、ActiveDirectoryDefaultやActiveDirectoryInteractiveなどの最新の認証方法に移行します。
Cosmos: 不正な id 文字はエスケープされなくなりました
以前の動作
以前は、複数の部分を含む複合キーから Cosmos id プロパティ値を生成するときに、Azure Cosmos DB プロバイダーは、Cosmos リソース id 値で無効な特定の文字をエスケープしました。
| Character | 次のようにエスケープします |
|---|---|
/ |
^2F |
\ |
^5C |
? |
^3F |
# |
^23 |
新しい動作
EF Core 11.0 以降では、生成された id 値でこれらの文字がエスケープされなくなります。
id値には、未加工のキー値が変更なしで含まれます。
id値が連結されている場合 (複合キーを使用する場合、または識別子in-id の動作をオプトインする場合) は、|文字が区切り記号として使用され、キー値に既に存在する|文字はすべてエスケープされ、あいまいさが回避されることに注意してください。 それ以外のエスケープ処理は行われません。
古いエスケープ動作は、 AppContext スイッチを設定することで再び有効にすることができます。
AppContext.SetSwitch("Microsoft.EntityFrameworkCore.EscapeIllegalCosmosIdCharacters", true);
なぜでしょうか
前のエスケープスキームは非挿入的でした。エスケープ文字 ^ 自体はエスケープされませんでした。 つまり、リテラル文字列^2Fを含むキー値は、idを含むキー値と同じ/を生成するため、個別の主キーを持つ 2 つのエンティティが同じ Cosmos ドキュメントにマップされるというサイレント データの破損が発生します。 エスケープを完全に停止すると、衝突の問題が修正されます。
緩和 策
アプリケーションで複合キーを使用し、値に文字 /、 \、 ?、または #を含めることができる場合は、次の点に注意してください。
-
既存のデータ: 以前に Cosmos DB に格納されたドキュメントには、古いエスケープ シーケンス (
idなど) を使用してPost|1|^2F値があります。 EF Core 11 にアップグレードすると、EF はエスケープされていないid値 (Post|1|/など) を生成し、それらの既存のドキュメントを見つけなくなります。 移行せずに既存のデータに引き続きアクセスするには、前述のAppContextスイッチを使用して古い動作に戻します。ただし、id 競合のバグが引き続き存在することに注意してください。 -
新しいデータ: 新しいアプリケーションまたはデータベースを作成する場合は、Cosmos DB リソースの
id値では無効であるため、キー値にこれらの無効な文字を使用しないでください。 詳細については、Azureドキュメントを参照してください。
Cosmos: プロジェクションが未定義と評価されたときにスローされる例外
以前の動作
以前は、パスのセグメントが Cosmos DB ドキュメントに存在しない (投影値が undefinedされる) オプションのリレーションシップを介してナビゲーションを介して匿名型または DTO プロジェクションのプロパティを射影する場合、動作に一貫性がありませんでした。
-
単一プロパティの匿名型または DTO プロジェクションでは、EF は
SELECT VALUEを使用してクエリを翻訳しました。これによって、投影された値がundefinedされたドキュメントは自動的に除外されます。 これは、返された結果が予想よりも少なく、データが不足していることを示さないことを意味します。 -
マルチプロパティ匿名型または DTO プロジェクションでは、"Nullable オブジェクトに値が必要です" というメッセージを含む
InvalidOperationExceptionがスローされました。
たとえば、オプションの所有Associateを持つエンティティ Entityを指定すると、そのエンティティにはオプションの所有NestedAssociateがあります。
// Previously silently returned fewer results (undefined results were filtered out)
var singlePropResults = await context.Entities
.Select(x => new { x.Associate!.NestedAssociate!.Id })
.ToListAsync();
// Previously threw InvalidOperationException: Nullable object must have a value
var multiPropResults = await context.Entities
.Select(x => new { x.Associate!.NestedAssociate!.Id, x.Associate!.NestedAssociate!.String })
.ToListAsync();
新しい動作
EF Core 11.0 以降では、プロジェクションの一部がAzure Cosmos DBでundefinedと評価されると、どちらの場合もInvalidOperationExceptionがスローされます。 例外メッセージは次のとおりです。
プロジェクションの一部が未定義でした。結合演算子を使用して、可能な未定義の値を処理します。
なぜでしょうか
前の動作に一貫性がありませんでした。 単一プロパティプロジェクションでは、結果が自動的に破棄され、問題を示さずにデータを見逃しやすくなります。 新しい動作により、プロジェクションで未定義の値が検出されるたびに、一貫性のある予測可能なエラーレポートが保証されます。
緩和 策
IsDefinedを使用して、投影値が不足しているドキュメントをフィルターで除外します。
var results = await context.Entities
.Where(x => EF.Functions.IsDefined(x.Associate!.NestedAssociate!.Id))
.Select(x => new { x.Associate!.NestedAssociate!.Id })
.ToListAsync();
または、 CoalesceUndefined を使用して、 undefinedできるプロパティの既定値を指定します。
var results = await context.Entities
.Select(x => new
{
Id = EF.Functions.CoalesceUndefined(x.Associate!.NestedAssociate!.Id, Guid.Empty)
})
.ToListAsync();
影響が小さい変更
Cosmos: __jObject シャドウ プロパティが削除されました。シリアル化に使用されなくなった JObject
以前の動作
以前は、Azure Cosmos DB プロバイダーは、(Newtonsoft.Jsonから) JObject型の"__jObject"という名前のシャドウ プロパティをすべてのエンティティ型に追加しました。 このプロパティには、Cosmos DB との間で送受信される生の JSON ドキュメントが含まれており、マップされていないデータまたは生データにアクセスできます。
var order = await context.Orders.FirstAsync();
var rawJson = context.Entry(order).Property<JObject>("__jObject").CurrentValue;
var billingAddress = rawJson["BillingAddress"]?.Value<string>();
EF Core は、すべてのドキュメントのシリアル化と逆シリアル化に Newtonsoft.Json ( JObject 経由) を内部的に使用します。
新しい動作
EF Core 11 以降では、 __jObject シャドウ プロパティは存在しなくなりました。 EF Core では、ドキュメントのシリアル化と逆シリアル化に System.Text.Json (Utf8JsonReader/Utf8JsonWriter) が使用されるようになり、 Newtonsoft.Jsonに依存しなくなりました。
"__jObject" プロパティにアクセスすると、InvalidOperationExceptionがスローされます。
なぜでしょうか
JObjectベースのアプローチでは、Newtonsoft.Jsonに依存し、パフォーマンスの向上が制限されている必要がありました。
System.Text.Jsonに切り替えると、EF Core Cosmos が他の.NET エコシステムに合わせられ、マテリアライザーのパフォーマンスが大幅に向上します。
緩和 策
生の JSON ドキュメントにアクセスするには、__jObjectに依存するのではなく、CosmosClientを直接使用します。
var cosmosClient = context.Database.GetCosmosClient();
var container = cosmosClient.GetContainer("myDatabase", "myContainer");
var response = await container.ReadItemAsync<JsonElement>("1", new PartitionKey("1"));
var billingAddress = response.Resource.GetProperty("BillingAddress").GetString();
詳細については、「Azure Cosmos DBでの非構造化データの操作」を参照してください。
SQL Server互換性レベルが既定で 160 に設定されるようになりました
以前の動作
以前は、SQL Server互換性レベルを明示的に構成せずに UseSqlServer を使用する場合、EF Core は既定で互換性レベル 150 に設定され、SQL Server 2019 に対応します。
新しい動作
EF Core 11.0 以降では、UseSqlServer の既定値は互換性レベル 160 で、SQL Server 2022 に対応します。 これにより、EF は既定で SQL Server 2022 機能を使用する SQL を生成できます。 たとえば、一部のクエリでは、LEAST、GREATEST、Math.Min、Math.Max、いくつかのLeastGreatestTakeパターンの翻訳など、/とSkipが使用されるようになりました。
データベースが SQL Server 2019 以前で実行されている場合、または互換性レベルが 160 未満で構成されている場合は、EF Core によって生成された一部の SQL がデータベースでサポートされなくなった可能性があります。
なぜでしょうか
SQL Server 2022 は数年間使用でき、互換性レベル 160 を既定で使用すると、EF Core は新しいSQL Server バージョンに対して、よりシンプルで効率的な SQL を生成できます。
緩和 策
データベースで互換性レベル 160 がサポートされていない場合は、データベースでサポートされている互換性レベルを使用するように EF Core を構成します。
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("<connection string>", o => o.UseCompatibilityLevel(150));
}
詳細については、SQL Server互換性レベルのドキュメントを参照してください。
移行が見つからないときに EF Core が既定でスローされるようになりました
以前の動作
以前は、アセンブリに移行がないデータベースで Migrate または MigrateAsync を呼び出すときに、EF Core は情報メッセージをログに記録し、変更を適用せずに返しました。
新しい動作
EF Core 11.0 以降では、アセンブリに移行が見つからない場合、EF Core は既定で例外をスローします。 これは、EF 9.0 で導入されたPendingModelChangesWarning動作と一致します。
なぜでしょうか
通常、移行が存在しない場合に Migrate() または MigrateAsync() を呼び出すと、構成が正しくないことを示します。 EF Core では、データベースをサイレントに続行して間違っている可能性がある状態のままにするのではなく、開発者にすぐにこの問題を通知するようになりました。
緩和 策
移行を行わずに意図的に Migrate() を呼び出す場合 (たとえば、他の方法でデータベース スキーマを管理するため)、 Migrate() 呼び出しを削除するか、警告を構成して例外を抑制します。
options.ConfigureWarnings(w => w.Ignore(RelationalEventId.MigrationsNotFound))
または、スローする代わりにイベントをログに記録します。
options.ConfigureWarnings(w => w.Log(RelationalEventId.MigrationsNotFound))
EFOptimizeContext MSBuild プロパティが削除されました
以前の動作
以前は、 EFOptimizeContext MSBuild プロパティを true に設定して、ビルドまたは発行中にコンパイル済みモデルとプリコンパイル済みクエリ コードの生成を有効にできました。
<EFOptimizeContext Condition="'$(Configuration)'=='Release'">true</EFOptimizeContext>
新しい動作
EF Core 11.0 以降では、 EFOptimizeContext MSBuild プロパティが削除されました。 コード生成は、 EFScaffoldModelStage プロパティと EFPrecompileQueriesStage プロパティを使用して排他的に制御されるようになりました。
PublishAOTが true に設定されている場合、追加のプロパティを必要とせずに、発行中にコード生成が自動的に有効になります。
なぜでしょうか
EFScaffoldModelStageプロパティとEFPrecompileQueriesStageプロパティでは、コード生成が発生するタイミングをきめ細かく制御できます。
EFOptimizeContext は冗長有効化ゲートでした。
緩和 策
EFOptimizeContextの使用法をEFScaffoldModelStageプロパティとEFPrecompileQueriesStageプロパティに置き換えます。 これらは、 publish または build に設定して、コード生成が発生するステージを制御できます。
<EFScaffoldModelStage>publish</EFScaffoldModelStage>
<EFPrecompileQueriesStage>publish</EFPrecompileQueriesStage>
その他の値 (たとえば、 none) は、対応する生成を無効にします。
PublishAOTに設定true場合、発行時にコード生成が自動的に有効になり、追加の構成は必要ありません。
EF ツール パッケージが Microsoft.EntityFrameworkCore.Design を参照しなくなりました
以前の動作
以前は、Microsoft.EntityFrameworkCore.Tools パッケージと Microsoft.EntityFrameworkCore.Tasks NuGet パッケージは、Microsoft.EntityFrameworkCore.Design に依存していました。
新しい動作
EF Core 11.0 以降、Microsoft.EntityFrameworkCore.Tools および Microsoft.EntityFrameworkCore.Tasks NuGet パッケージは、Microsoft.EntityFrameworkCore.Design に依存しなくなりました。
なぜでしょうか
Microsoft.EntityFrameworkCore.Design のコードに対するハード依存関係はなく、この依存関係は、古いフレームワークを対象とするプロジェクトで最新の Microsoft.EntityFrameworkCore.Tools を使用するときに問題を引き起こしていました。
緩和 策
プロジェクトがツール パッケージを通じて推移的に取り込まれるMicrosoft.EntityFrameworkCore.Designに依存している場合は、プロジェクトに直接参照を追加します。
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="11.0.0" PrivateAssets="all" />
SqlVector プロパティが既定で読み込まれなくなりました
以前の動作
以前は、 SqlVector<T> プロパティを使用してエンティティにクエリを実行する場合、EF Core は SELECT ステートメントにベクター列を含め、返されたエンティティにプロパティを設定しました。
新しい動作
EF Core 11.0 以降では、エンティティを具体化するときに、 SqlVector<T> プロパティが SELECT ステートメントに含まれないようになりました。 返されたエンティティのプロパティはnullとなります。
ベクター プロパティは、WHEREやORDER BYを含め、VectorDistance()句とVectorSearch()句で引き続き使用できます。これらはエンティティ プロジェクションには含まれません。
なぜでしょうか
ベクター列は非常に大きく、数百または数千の浮動小数点値を含むことができます。 ほとんどの場合、ベクターはデータベースに書き込まれ、検索に使用され、読み戻す必要はありません。 既定で SELECT から除外すると、不要なデータ転送が回避されます。
緩和 策
注
ベクター プロパティを自動読み込みに戻すメカニズムは、EF Core 11 リリースの後半で導入される予定です。
ベクター値を読み戻す必要がある場合は、明示的なプロジェクションを使用します。
var embeddings = await context.Blogs
.Select(b => new { b.Id, b.Embedding })
.ToListAsync();
Cosmos: 空の所有コレクションが null ではなく空のコレクションを返すようになりました
以前の動作
以前は、所有するコレクションに項目が含まれなかったAzure Cosmos DB プロバイダーを介してエンティティに対してクエリを実行する場合、コレクション プロパティは具体化されたエンティティに対して nullでした。
新しい動作
EF Core 11.0 以降では、Azure Cosmos DB プロバイダーは空の所有コレクションを正しく初期化し、null ではなく空のコレクションを返します。
なぜでしょうか
空の所有コレクションを null として具体化する以前の動作はバグでした。
緩和 策
コレクションが空であることを検出するために null の所有コレクション プロパティをコードで明示的にチェックする場合は、コレクションが常に初期化されるため、これらのチェックは単に削除できます。
// Before
if (entity.OwnedCollection is null or { Count: 0 })
{
// treated as empty
}
// After
if (entity.OwnedCollection is { Count: 0 })
{
// treated as empty
}
Cosmos: 既定の識別子プロパティの名前がモデル Discriminator になりました
以前の動作
EF は、JSON ドキュメントが表すエンティティ型を識別する識別子プロパティを自動的に追加します。 JSON ドキュメント内のこのプロパティの名前は、EF Core 9.0 で Discriminator から $type に変更されました。 これを実現するために、EF では、EF モデルと格納されている JSON ドキュメントの両方で、識別子プロパティの名前として $type を使用しました。
$typeは有効な C# 識別子ではないため、結果として得られるシャドウ プロパティ名により、ネイティブ AOT で使用されるコンパイル済みモデルおよびプリコンパイル済みクエリに対して無効なコードが生成されました。
新しい動作
EF Core 11.0 以降では、既定の識別子プロパティの名前が EF モデル Discriminator にもう一度付けられますが、JSON ドキュメントに書き込まれる名前は変更されず、既定では $type のままです。 つまり、モデル プロパティ名と JSON プロパティ名が切り離されました。
-
entityType.FindDiscriminatorProperty().Nameは、Discriminatorを返します。 -
entityType.FindDiscriminatorProperty().GetJsonPropertyName()は、$typeを返します。
保存されているドキュメントの形式はこの変更の影響を受 けないため 、既存のデータは変更なしで引き続き機能します。
なぜでしょうか
EF は、生成された一部の C# 識別子 (シャドウ プロパティ変数名など) を、プロパティ名などのモデル メタデータから派生させます。
$typeは有効な C# 識別子ではないため、それをモデル プロパティ名として使用すると、コンパイル済みモデルとプリコンパイル済みクエリに対してコンパイル不可能なコードが生成されました。
$typeをドキュメントに書き込むときにモデル プロパティDiscriminator (有効な識別子) に名前を付けると、ディスク上の形式を変更することなく、生成されたコードが有効なまま保持されます。
緩和 策
保存されたドキュメントは影響を受けず、 $typeを引き続き使用するため、ほとんどのアプリケーションではアクションは必要ありません。
コードが 、モデル プロパティ名、 $type (クエリまたはクエリ フィルターの Property 、またはメタデータ内のプロパティの検索など) によって識別子を参照する場合は、代わりに Discriminator を使用するように更新します。
// Before
var query = context.Set<Session>().Where(e => EF.Property<string>(e, "$type") == "Lecture");
// After
var query = context.Set<Session>().Where(e => EF.Property<string>(e, "Discriminator") == "Lecture");
モデル全体の JSON 識別子プロパティ名を 1 つの場所で変更するには (たとえば、モデル プロパティ名に合わせる)、各エンティティ型を個別に構成するのではなく、モデル レベルの HasEmbeddedDiscriminatorName API を使用します。
modelBuilder.HasEmbeddedDiscriminatorName("Discriminator");
特定のエンティティ型の JSON 名のみを変更するには (たとえば、モデル プロパティ名に合わせる)、識別子プロパティの JSON 名を ToJsonPropertyに構成します。
modelBuilder.Entity<Session>().Property<string>("Discriminator").ToJsonProperty("Discriminator");
識別子プロパティの名前もモデル内の $type 前の動作に戻すには、 HasDiscriminatorを使用してその名前を明示的に構成します。 これにより無効な C# 識別子が再導入され、コンパイル済みモデルまたはプリコンパイル済みクエリを使用する場合は推奨されないことに注意してください。
modelBuilder.Entity<Session>().HasDiscriminator<string>("$type");
Cosmos: 固定小数点型に具体化するときに浮動小数点値が切り捨てられるようになりました
以前の動作
以前は、クエリ プロジェクションが浮動小数点値 (たとえば、Cosmos によって0.75として返される3 / 4などの数値式の結果) を返し、ターゲット プロパティが固定小数点型 (int、long、decimalなど) であった場合、EF Core は値を丸めます。 たとえば、 0.75 は 1として具体化されます。
新しい動作
EF Core 11 以降では、このような値は丸 めではなく切り捨てられます 。
0.75標準.NET整数の切り捨て動作 ((int)0.75 == 0) に一致する0として具体化されるようになりました。
なぜでしょうか
切り捨ては、明示的な数値変換の標準的な.NET動作であり、他のプロバイダーの動作と一致します。 前の丸め動作はバグでした。
緩和 策
前の丸め動作に依存していた場合は、 Math.Roundを使用してクエリに明示的な丸めを適用します。
var result = await context.Products
.Select(p => (int)Math.Round((double)p.Int / (p.Int + 1)))
.SingleAsync();
明示的なキーを持たない所有 JSON コレクションは廃止されました
以前の動作
以前は、 ToJson を介して JSON 列にマップされた所有エンティティ型は、明示的な主キーを構成せずにコレクションとして使用できました。 EF Core は、コレクション内の各項目を識別するために、バックグラウンドで序数 (位置) キーを合成します。
public class Blog
{
public int Id { get; set; }
public List<Post> Posts { get; set; } = new();
}
public class Post
{
// No key property
public required string Title { get; set; }
public required string Content { get; set; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder.Entity<Blog>().OwnsMany(b => b.Posts, b => b.ToJson());
新しい動作
EF Core 11.0 以降では、明示的なキーを使用せずに所有 JSON コレクションを構成すると、 OwnedEntityMappedToJsonCollectionWarning 警告が生成されます。 マッピングは引き続き機能しますが、現在は非推奨と見なされ、今後のリリースで削除される予定です。
明示的な主キーを持つ所有 JSON エンティティと、コレクション以外の所有 JSON 参照は、この変更の影響を受けません。
なぜでしょうか
JSON マッピングを含め、複合型は EF Core 10 で完全にサポートされました。 複合型は、JSON ドキュメントの所有型よりも適しています。値セマンティクスがあり、ID がないため、所有エンティティ型 (エンティティ型) を使用して、基本的に別のドキュメントに埋め込まれた値をモデル化する際に発生する多くの問題を回避できます。 特に、明示的なキーのない所有 JSON コレクションは、既知の制限事項とコーナー ケースがある合成序数キーに依存していました。
緩和 策
推奨される軽減策は、型を複合型に移行することです。これは、型を JSON にマップする推奨される方法です。
protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder.Entity<Blog>().ComplexCollection(b => b.Posts, b => b.ToJson());
あるいは、所有型のマッピングを保持する必要がある場合は、所有型に非シャドウ主キーを設定します。 キーが構成されると、警告は適用されなくなります。
public class Post
{
public int Id { get; set; }
public required string Title { get; set; }
public required string Content { get; set; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder.Entity<Blog>().OwnsMany(b => b.Posts, b =>
{
b.ToJson();
b.HasKey(p => p.Id);
});
すぐに移行できない場合は、 ConfigureWarningsを使用して警告を抑制できます。
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.ConfigureWarnings(w => w.Ignore(CoreEventId.OwnedEntityMappedToJsonCollectionWarning));
Property プリミティブ コレクションを構成しなくなりました
以前の動作
以前は、CLR 型がコレクション (List<int> など) であるメンバーに対してPropertyを呼び出すと、その型に基づいてモデルの最終処理時にプロパティをプリミティブ コレクションに昇格できるため、メンバーがプリミティブ コレクションとして構成される可能性があります。
新しい動作
EF Core 11.0 以降では、プロパティがプリミティブ コレクションであるかどうかは、プロパティの構成時に完全に決定されます。 プリミティブ コレクションは、 PrimitiveCollection で構成する (または規則によって 1 つとして検出される) 必要があります。 Property では、メンバーは常に非コレクション (スカラー) プロパティとして構成され、プリミティブ コレクションへの最終化時の昇格はなくなりました。
なぜでしょうか
要素型を最終処理時の懸念事項として扱うと、不整合やバグが発生しました。 たとえば、プロパティはプリミティブ コレクションとして検出できますが、後で継承された値コンバーターを介してスカラーに解決され、モデルの最終処理で InvalidCastException が発生した古い要素型が残されます。 プリミティブ コレクションを作成時の懸念事項にすることで、 byte[]などの場合でもマッピングが明確になります。それ以外の場合は、メンバーをバイナリ スカラーとしてマップするか、バイトのコレクションとしてマップするかは不明です。
緩和 策
プリミティブ コレクションを構成するために Property に依存している場合は、代わりに PrimitiveCollection に切り替えます。
protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder.Entity<Blog>().PrimitiveCollection(b => b.Tags);
プリミティブ コレクションは規則によって検出されるため、ほとんどの場合、変更は必要ありません。
同時変更が検出されたときに分割クエリがスローされるようになりました
以前の動作
以前は、分割クエリ ( AsSplitQuery() を使用) で、分割クエリの SQL ステートメント間の同時データ変更によって、順序が正しくなく、または孤立した子行が検出された場合、EF Core は影響を受ける子コレクションを暗黙的に破棄しました。 結果は、関連する行がまだ存在していても、空のコレクションを持つエンティティでした。例外はスローされず、警告はログに記録されませんでした。
新しい動作
EF Core 11.0 以降では、データの同時変更が原因で分割クエリの結果を関連付けられない場合、EF Core は DbQueryConcurrencyException をスローします。 例外メッセージは状況を説明し、修復を提案します。
クエリの実行中にデータが同時に変更されたため、分割クエリの結果を関連付けできませんでした。 クエリを再実行するか、シリアル化可能なトランザクションまたはスナップショット トランザクション内で実行して、同時変更を防ぎます。
なぜでしょうか
間違ったデータ (関連する行を持つエンティティの空のコレクション) を自動的に返す方が、エラーが発生するよりもはるかに悪くなります。 このシナリオは、本質的に、データベースがステートメント間で変更されたときに、分割クエリでデータ整合性が保証されていないことが原因で発生します。 再トリガー可能な例外をスローすると、問題が表示され、呼び出し元に復旧への明確なパスが提供されます。
緩和 策
最も簡単な軽減策は、クエリを再実行することです。同時変更は一時的であり、再試行は通常成功します。
const int maxRetries = 3;
List<Blog> blogs;
for (var attempt = 0; attempt < maxRetries; attempt++)
{
try
{
blogs = await context.Blogs
.Include(b => b.Posts)
.AsSplitQuery()
.ToListAsync();
break;
}
catch (DbQueryConcurrencyException) when (attempt < maxRetries - 1)
{
// Retry on concurrent modification
}
}
または、分割クエリをシリアル化可能なトランザクションまたはスナップショット トランザクションにラップして、同時変更が結果に影響しないようにします。
await using var transaction =
await context.Database.BeginTransactionAsync(IsolationLevel.Serializable);
var blogs = await context.Blogs
.Include(b => b.Posts)
.AsSplitQuery()
.ToListAsync();
await transaction.CommitAsync();
再試行もトランザクションも許容できない場合は、常に一貫性のある 1 つのクエリ (AsSingleQuery()) に切り替えます。
var blogs = await context.Blogs
.Include(b => b.Posts)
.AsSingleQuery()
.ToListAsync();
Microsoft.Data.Sqlite の破壊的変更
注
SQLitePCLRaw は、Microsoftによって所有または管理されていない、コミュニティが管理する外部ライブラリです。 Microsoft。Data.Sqlite は、SQLite 接続に依存します。
概要
| 破壊的変更 | 影響 |
|---|---|
| Microsoft。Data.Sqlite で .NET Framework がサポートされなくなりました | ミディアム |
| 一部の SQLitePCLRaw バンドル パッケージは保守されなくなりました | ミディアム |
| SQLite で UWP とクラシック Xamarinがサポートされなくなりました | 低 |
影響が中程度の変更
Microsoft。Data.Sqlite で .NET Framework がサポートされなくなりました
以前の動作
以前は、ターゲット netstandard2.0をMicrosoft.Data.SqliteしてMicrosoft.Data.Sqlite.Coreしました。これによって、.NET Framework アプリケーションから使用することができました。
新しい動作
Microsoft.Data.Sqlite 11.0 以降では、両方のパッケージがnet10.0のみを対象としています。 .NET Framework アプリケーションでは、Microsoft.Data.Sqlite 11.0 を参照したり使用したりできなくなります。
なぜでしょうか
netstandard2.0ターゲットは、サポートされていない古い.NETターゲットがサポートされているように見え、DateOnlyやTimeOnlyのサポートなどの API の違いもマスクされています。 サポートされている最小.NETバージョンを明示的にターゲットにすると、サポートされているプラットフォームサーフェスが明確になります。
緩和 策
可能であれば、アプリケーションを .NET 10 以降に移動します。
.NET Framework を引き続き使用する必要がある場合は、最新の Microsoft.Data.Sqlite 10.0.x サービス リリースを利用してください。 10.0.x 行ではSQLitePCLRaw.bundle_e_sqlite3が使用されるため、.NET Framework アプリケーションは、更新プログラムの受信を停止した後でも、参照SQLitePCLRaw.bundle_e_sqlite3バージョンMicrosoft.Data.Sqlite更新できます。
一部の SQLitePCLRaw バンドル パッケージは保守されなくなりました
以前の動作
以前は、 SQLitePCLRaw.bundle_e_sqlcipher、 SQLitePCLRaw.bundle_sqlite3、 SQLitePCLRaw.bundle_winsqlite3、 SQLitePCLRaw.bundle_green、および SQLitePCLRaw.bundle_e_sqlite3mc パッケージは、対応する SQLite プロバイダーで SQLitePCLRaw を構成するための便利な方法を提供しました。
新しい動作
SQLitePCLRaw.bundle_winsqlite3、SQLitePCLRaw.bundle_sqlite3、SQLitePCLRaw.bundle_winsqlite3、SQLitePCLRaw.bundle_green、およびSQLitePCLRaw.bundle_e_sqlite3mcのパッケージは、SQLitePCLRaw メンテナーによって更新されなくなりました。
SQLitePCLRaw.Core 3.0 以降と互換性がないため、これらのパッケージを 3.x と共に直接参照するアプリケーションSQLitePCLRaw.Core競合が発生します。 アプリケーションは、将来の破損を避けるために推奨される代替手段に移行する必要があります。
なぜでしょうか
SQLitePCLRaw メンテナーは、バージョン 3.0 でこれらのバンドルを削除しました。各バンドルには 1 行の構成コードのみが含まれており、基になるプロバイダー パッケージが引き続きサポートされている間、不要なパッケージ化のオーバーヘッドが追加されました。
SQLitePCLRaw.bundle_e_sqlcipher パッケージは特に影響を受け、ほとんど維持されない暗号化対応ビルドを提供しました。これは、脆弱性の修正プログラムが適用されない可能性がある暗号化ソフトウェアのセキュリティ上の懸念事項です。
緩和 策
SQLitePCLRaw.bundle_e_sqlcipherを使用している場合(暗号化が有効な SQLite) を使用して、次のいずれかの代替方法に移行します。
SQLite3 の複数の暗号: NuGet パッケージは SQLite3MultipleCiphers-NuGet から入手できます。
SQLite3MC.PCLRaw.bundleと共に参照Microsoft.Data.Sqlite.Core:<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="11.0.0" /> <PackageReference Include="SQLite3MC.PCLRaw.bundle" Version="2.x.x" />新しいデータベースを暗号化する場合、または SQLCipher で暗号化された既存のデータベースを開く場合は、URI パラメーター (例:
Data Source=file:example.db?cipher=sqlcipher&legacy=4) を使用して暗号スキームを構成します。 詳細については、 SQLCipher で暗号化された既存のデータベースを開く方法 を参照してください。SQLite 暗号化拡張機能 (SEE): SQLite チームからの公式の暗号化実装。 有料ライセンスが必要です。 NuGet オプションについては、 https://sqlite.org/com/see.html および SourceGear の SQLite ビルド サービス を参照してください。
SQLCipher: Zetetic からサポートされているビルドを購入するか、オープンソース コードを自分でビルドします。
SQLitePCLRaw.bundle_sqlite3またはSQLitePCLRaw.bundle_winsqlite3を使用している場合は、バンドル パッケージを対応するプロバイダー パッケージに置き換えます。
<!-- Old -->
<PackageReference Include="SQLitePCLRaw.bundle_sqlite3" Version="2.x.x" />
<!-- or -->
<PackageReference Include="SQLitePCLRaw.bundle_winsqlite3" Version="2.x.x" />
<!-- New -->
<PackageReference Include="SQLitePCLRaw.provider.sqlite3" Version="3.x.x" />
<!-- or -->
<PackageReference Include="SQLitePCLRaw.provider.winsqlite3" Version="3.x.x" />
SQLite を使用する前に明示的な初期化を追加します。
// For sqlite3
static void Init()
{
SQLitePCL.raw.SetProvider(new SQLitePCL.SQLite3Provider_sqlite3());
}
// For winsqlite3
static void Init()
{
SQLitePCL.raw.SetProvider(new SQLitePCL.SQLite3Provider_winsqlite3());
}
SQLitePCLRaw.bundle_e_sqlite3mcを使用している場合は、パッケージ参照をSQLite3MC.PCLRaw.bundleに置き換えます。
<!-- Old -->
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3mc" Version="2.x.x" />
<!-- New -->
<PackageReference Include="SQLite3MC.PCLRaw.bundle" Version="2.x.x" />
SQLitePCLRaw.bundle_greenを使用している場合は、SQLitePCLRaw.bundle_e_sqlite3に切り替えます。 または、SQLitePCLRaw.config.e_sqlite3SourceGear.sqlite3などの別のネイティブ ライブラリ パッケージと組み合わせて使用します。これにより、SQLite バージョンを個別に更新できます。
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="3.x.x" />
iOS のみを対象とし、システム SQLite ライブラリを使用する場合は、プロバイダーを直接参照し、明示的に初期化します。
<PackageReference Include="SQLitePCLRaw.Core" Version="3.x.x" />
<PackageReference Include="SQLitePCLRaw.provider.sqlite3" Version="3.x.x" />
static void Init()
{
SQLitePCL.raw.SetProvider(new SQLitePCL.SQLite3Provider_sqlite3());
}
詳細については、 SQLitePCLRaw および SQLitePCLRaw3.0 リリース ノートで使用する SQLite 暗号化オプションを参照してください。
影響が小さい変更
SQLite で UWP とクラシック Xamarinがサポートされなくなりました
以前の動作
以前SQLitePCLRaw.bundle_e_sqlite3には、ユニバーサル Windows プラットフォーム (UWP)とクラシック Xamarin (Xamarin.iOS、Xamarin用のネイティブ SQLite ビルドが含まれていました。Android、およびXamarin。Mac) ターゲット。
新しい動作
SQLitePCLRaw.bundle_e_sqlite3 2.1.12 (Microsoft.Data.Sqlite 11.0 によって参照) 以降、UWP とクラシック Xamarinのネイティブ ビルドは含まれなくなりました。 これらのプラットフォームを対象とするアプリケーションでは、バンドルされたネイティブ SQLite ライブラリを使用できなくなりました。
なぜでしょうか
SQLite 3.53.0 (SQLitePCLRaw.bundle_e_sqlite3 2.1.12 によって出荷) では、UWP とクラシック Xamarinがサポートされなくなりました。 SQLitePCLRaw 保守担当者は、新しいアップストリーム SQLite リリースに対応するために、これらのビルドを削除しました。
緩和 策
UWP アプリケーションをWindows アプリ SDKおよび従来のXamarin アプリケーションに移行して、最新の.NETでサポートされている.NET MAUIに移行します。
UWP またはクラシック Xamarinを使用する必要がある場合は、これらのプラットフォームのネイティブ ビルドをまだ含む以前のバージョンのSQLitePCLRaw.bundle_e_sqlite3を使用してください。
.NET