ORM Entity Frameworkにはアキレス腱があります。 これは、CRUD操作から、作成と読み取りのみが最適に実行されるという事実から成ります。 [ボックス内の更新と削除]オプションでは、最初にデータベースからレコード全体を読み取る必要があり、その後でのみ更新できます。 そして、はい、レコードを削除するには、最初にそれも読む必要があります。
つまり 残念なプログラマーは
using (var ctx = new ShopEntities()) { foreach (var u in ctx.Users) { ctx.Users.Remove(u); } ctx.SaveChanges(); }
しかし、EntityFramework.Extendedパッケージのリリースにより、状況は根本的に変化しています。
そのため、コマンド「Install-Package EntityFramework.Extended」を使用して、リポジトリからパッケージをインストールします。 次に、名前空間「EntityFramework.Extensions」を接続します。
そして魔法が始まります。
削除は次のようになります。
using (var ctx = new ShopEntities()) { var itemsDeleted = ctx.Users.Delete(u => u.Orders.Count > 10);
ちなみに、サーバーに飛んだものを見るのは不必要ではありません。
そんな依頼でした
DELETE [dbo].[Users] FROM [dbo].[Users] AS j0 INNER JOIN ( SELECT [Project1].[ID] AS [ID] FROM ( SELECT [Extent1].[ID] AS [ID], (SELECT COUNT(1) AS [A1] FROM [dbo].[Orders] AS [Extent2] WHERE [Extent1].[ID] = [Extent2].[UserID]) AS [C1] FROM [dbo].[Users] AS [Extent1] ) AS [Project1] WHERE [Project1].[C1] > 10 ) AS j1 ON (j0.[ID] = j1.[ID]) go
ご覧のとおり、これは条件付きの正直な(不器用ではありますが)グループ削除要求です。
同様に、レコードを更新します。 更新する前に、データベースからデータを読み取る必要がなくなりました。 同時に、レコード内の既存のデータを使用でき、定数のみに制限されません。
using (var ctx = new ShopEntities()) { var itemsUpdated = ctx.Users.Where(u => u.Orders.Count > 0).Update(u => new User { BonusCount = u.BonusCount + 1 });
プロファイラーでSQLクエリを確認します。
UPDATE [dbo].[Users] SET [BonusCount] = [BonusCount] + 1 FROM [dbo].[Users] AS j0 INNER JOIN ( SELECT [Project1].[ID] AS [ID] FROM ( SELECT [Extent1].[ID] AS [ID], (SELECT COUNT(1) AS [A1] FROM [dbo].[Orders] AS [Extent2] WHERE [Extent1].[ID] = [Extent2].[UserID]) AS [C1] FROM [dbo].[Users] AS [Extent1] ) AS [Project1] WHERE [Project1].[C1] > 0 ) AS j1 ON (j0.[ID] = j1.[ID]) go
これらは、この拡張パッケージをインストールする価値があるため、2つの主要な機能です。
しかし、砂糖もあります。 パッケージの作成者は、サンプリングのリクエストを蓄積してから、それらを1つのアプローチで実行するように提案しています。 これを行うには、具体化する前にデータをFuture()としてマークし、オブジェクトのいずれかを具体化すると、残りは自動的に具体化されます。
using (var ctx = new ShopEntities()) { var alexUsers = ctx.Users.Where(u => u.Name == "Alex").Future(); var usersWithOrders = ctx.Users.Where(c => c.Orders.Any()).Future(); foreach (var item in alexUsers)
しかし、それはSQLクエリでした
Future拡張機能に加えて、FutureCount、FutureFirstOrDefault、FutureValueも使用できます。
しかし、それだけではありません。 まれにしか変更されないデータに対する頻繁なリクエストを処理するモジュールがあると想像してください。 たとえば、ユーザー認証。 結果をキャッシュしますか? お願いします。 コードからわかるように、キャッシュはコンテキストによって制限されませんが、再作成後も関連性を保ちます。
for (int i = 0; i < 2; i++) { using (var ctx = new ShopEntities()) { var alexUsers = ctx.Users.Where(u => u.Name == "Alex").FromCache(); foreach (var item in alexUsers)
FromCacheメソッドには、キャッシュ時間を指定するためのオーバーロードがあります。
したがって、EntityFramework.Extendedのインストールと使用は、EntityFrameworkの子供時代の病気を排除するだけでなく、ストアドプロシージャの下位レベルに行かずに高負荷の場所でそれを加速させます。