質問: クライアントから提供されたデータベースの複雑なオブジェクトを更新しようとすると、web-apiのsqlデータベースのef-coreでいくつかの問題が発生します。 詳細な例:1からnの「投稿」を持つオブジェクト「ブログ」をクライアントから受信し、データベース上のこの既存のオブジェクトを更新しようとした場合、次のようにする必要があります。 1. 主キーが設定されていることを確認し、 `dbContext.Update(blogFromClient)`使用します 2. データベースからの投稿を含めながらブログをロードして追跡し、クライアントからの変更をこのオブジェクトにパッチし、 `SaveChanges()`を使用します アプローチ(1)を使用すると、次の問題が発生しました。 1. データベース上の既存のブログの既存の投稿は、クライアントが投稿しなくなったときに削除されず、手動で把握して削除する必要があります。 2. ブログの依存関係(たとえば、「作成者」としての「ユーザー」)がすでに`ChangeTracker`場合の追跡の問題( `"is already been tracked"` )の`ChangeTracker` 3. リポジトリパターンを使用している間は、実際の`DbContext`を使用せずにビジネスロジックを単体テストすることはできません(追跡エラーは存在しません) 4. `DbContext`で`InMemoryDatabase`をテストに使用すると、外部キーの例外や計算列などに依存できなくなります アプローチ(2)を使用する場合: 1. 更新された関係を簡単に管理し、オブジェクトを簡単に追跡できます 2. 実際には不要なオブジェクトをロードするため、パフォーマンスが低下する 3. `AutoMapper`などのツールを使用してnnの関係を持つオブジェクトを自動的にマッピングすることはできませんが、 `ef core`によって正しいトラックを維持しながら、多くの手動のものをマッピングする必要があります(一部のオブジェクトはリストから削除され、同じプライマリで再度追加されるため、いくつかの主キーエラーが発生しますキー、挿入時に主キーを設定できないため許可されません) 4. nnリレーションはこれによって簡単に損傷を受ける可能性があります。データベースにはnnブログが投稿される可能性があるため、ブログの投稿はその投稿と同じリレーションを保持します。 1つのリレーションのみ(ブログへの投稿、ブログへの投稿ではなく、SQLでも同じ)が投稿され、他の部分がリストから削除された場合、efコアはこのエントリを「削除済み」として追跡します。 バニラSQLではこれを管理します 1. ブログから投稿への既存の関係をすべて削除する 2. 投稿自体を更新する 3. すべての新しい関係を作成する efコアでは、バルクリレーションを削除するなどのステートメントを、それらを事前にロードしてから各リレーションの詳細な追跡を行わずに記述することはできません。 クライアントから「新しい」データを取得しながら、深い関係を持つ複雑なオブジェクトの更新を処理するためのベストプラクティスはありますか?
回答: 正しい方法は#2:「データベースからの投稿を含めながらブログをロードして追跡し、クライアントからの変更をこのオブジェクトにパッチし、 `SaveChanges()`を使用する」です。 あなたの懸念に関して: > 実際には不要なオブジェクトをロードするため、パフォーマンスが低下する > > これを必要としないというのはあなたの誤りです。実際にこれが必要なのは、監査プロップなどの変更してはならないものを含め、すべての単一のエンティティおよび関連エンティティにすべての単一のプロパティを投稿するべきではないためです。すべてのプロパティを投稿*しないと* 、保存時に結果がnullになります。したがって、唯一の正しいパスは、常にデータベースから完全なデータセットをロードし、ポストされたものを介してそれを変更することです。それを他の方法を行うと問題が発生し、完全に、完全に100%間違っている*でしょう* 。 > `AutoMapper`などのツールを使用してnnの関係を持つオブジェクトを自動的にマッピングすることはできませんが、 `ef core`による正しいトラックを維持するため、多くの手動のものをマッピングする必要があります。 > > ここで説明しているのは、自動マッピングの制限です。コレクション内のエンティティにエンティティをマッピングするために、ツールは各エンティティを一意に識別するものを何らかの方法で知る必要があります。もちろん、これは通常PKになりますが、AutoMapperはそのことを想定していません(想定すべきではありません)。代わりに、デフォルトの単純な動作は、宛先のコレクションをソースのコレクションで単純に置き換えることです。ただし、EFにとっては、コレクション内のすべてを削除してから、新しいアイテムをコレクションに追加するように見えます。これが問題の原因です。 次の2つの方法があります。まず、ソースのコレクションの小道具を無視して、手動でマッピングするだけです。マッピングにAutoMapperを引き続き使用できますが、エンティティを識別するもの(つまりAutoMapperのパーツ)の知識に基づいて、コレクション内の各アイテムを繰り返し処理して、マッピングする必要のある適切なアイテムと個別に照合する必要がありますわからない)。 2つ目は、AutoMapperがこれを簡単にするための追加ライブラリであるAutoMapper.Collection `AutoMapper.Collection` 。このライブラリの要点は、エンティティを識別する方法をAutoMapperに指示して、コレクションを正しくマップできるようにする機能を提供することです。このライブラリを利用して必要な構成を追加すると、コレクションがめちゃくちゃになることを心配することなく、通常どおりエンティティをマッピングできます。