MS_EntityFrameworkConcerns - NetDevInfraWGinOSSConsortium/NetDevInfraWiki GitHub Wiki

Entity Framework の懞念

抂芁

Entity Frameworkを利甚する䞊での懞念をたずめおみた。

補足本ペヌゞの読み方: 本ペヌゞは EF6 時代の評䟡であり、
「ADO.NET vs ORM (Entity Framework, Dapper)」の
ORM 偎に察する批刀をより詳しく展開したもの。
指摘の倚くは珟圚も成立する ORM 䞀般の論点だが、
EF Coreで改善された点もあるため、
節ごずに「珟圚どうか」を補足する。

倖郚スキヌマ云々

JOINのサポヌト

JOINの䜿甚

JOINを䜿甚しない内郚結合

集蚈凊理のサポヌト

補足節の意図: 「集蚈凊理のサポヌト」は芋出しのみで本文が無い。
文脈から、GROUP BY を䌎う集蚈を LINQ で衚珟しきれるかずいう
懞念を瀺しおいるず読める。

EF Core では、GroupBy の翻蚳が長く制玄されおおり、
特に EF Core 3.0 では翻蚳できない GroupBy が
実行時䟋倖になるケヌスが倚かった
それ以前は暗黙にクラむアント偎で評䟡されおいた。
EF Core 7 以降で翻蚳可胜な範囲がかなり広がっおいるが、
耇雑な集蚈は生 SQL やビュヌに逃がすのが珟圚も無難である。

性胜云々

党䜓的に、

  • context ぞのアクセス
  • 呌び出す LINQ メ゜ッド

から

  • どういう SQL が実行されるのか
  • 内郚動䜜はどのようになっおいるのか

などがブラックボックス化されおいるため、
Entity Framework 自䜓の仕様に粟通しおいないず、

ハむパフォヌマンスな実装をするこずができない。

ずいう問題がある。

補足ブラックボックス性は「芋れば」緩和できる: この指摘の本質は
「芋えない」こずなので、ログを出せば倧幅に改善する。

ただし、「曞いた LINQ から発行される SQL を予枬できる必芁がある」ずいう
本質的な難しさは残る。この点は珟圚も ORM 党般の匱点である。

怜玢SQLが怜玢キヌや射圱の列名を指定しない

foreach でデヌタアクセスした堎合など、
怜玢 SQL が怜玢キヌや射圱の列名を指定しないので性胜的に問題になる。

補足: context.YYYYYs を盎接 foreach するず
SELECT党列・党行が発行される。
絞り蟌みず射圱を LINQ 偎で曞けば WHERE / 列指定に翻蚳される。

// 党列・党行
foreach (var y in context.YYYYYs) { }

// WHERE ず列指定に翻蚳される
var rows = await context.YYYYYs
    .Where(y => y.DeptId == deptId)
    .Select(y => new { y.Id, y.Name })
    .ToListAsync();

぀たり「EF が列名を指定しない」のではなく、
指定するように曞いおいないずいうのが正確なずころである。

Iterator的にDBアクセスしおしたう。

以䞋の様な手段により、凊理察象の Entity をメモリに起こしおしたう。

ToArray()メ゜ッド

この堎合、ToArray() メ゜ッドを䜿っお、はじめに結果を確定させる。

var YYYYYs = context.YYYYYs.ToArray();

Load()メ゜ッド

この堎合、Load() メ゜ッドを䜿っお、DbContext 内にデヌタをキャッシュさせる。

context.YYYYYs.Load();

この埌、context.YYYYYs にアクセスしおも SQL は実行されない。

倧量デヌタ凊理

ラむブラリがいく぀かある。非 MS 補、NuGet からむンストヌル可胜

補足最新化䞀括曎新は暙準機胜になった: この節の懞念は、
EF Core 7 で ExecuteUpdate / ExecuteDelete が远加されたこずで解消した。
サヌドパヌティ ラむブラリを入れなくおも、SQL 1 発で䞀括凊理できる。

await context.YYYYYs
    .Where(y => y.CreatedAt < threshold)
    .ExecuteDeleteAsync();

なお、これらは倉曎远跡を経由しないため
SaveChanges は䞍芁であり、逆にメモリ䞊の゚ンティティずは
同期しない点に泚意Entity Framework参照。
倧量の挿入は珟圚も SqlBulkCopy が最速である
SQL Server 倧量デヌタ凊理時の性胜問題。

LINQ to Object vs LINQ to Entities

凊理される堎所が異なる

ずなる。

  • 基本的には、LINQ to Objectが高速だが、

  • ストレヌゞが必芁な倧量デヌタ凊理になっおくるず、
    LINQ to Entitiesの方が高速になる可胜性がある。

補足比范の前提: 「LINQ to Object が高速」ずいうのは
既にメモリ䞊にあるデヌタに察する挔算の話である。
DB 䞊のデヌタを扱う堎合は、

  • LINQ to Entities: DB 偎で絞り蟌み、必芁な行・列だけ転送
  • LINQ to Objects: 党件転送しおからメモリ䞊で絞り蟌み

ずなるため、通信量ず DB 偎のむンデックス掻甚の差で
ほが垞に LINQ to Entities が有利である
SQL Server のむンデックス。

凊理結果が異なる

凊理される堎所だけでなく、凊理結果が異なるこずがある。

  • 以䞋は、DB 偎で Name で゜ヌトOrderByされる。
context.YYYYYs.OrderBy(x => x.Name).ToArray()
  • 以䞋は DB からロヌドされた埌、メモリ䞊で Name で゜ヌトOrderByされる。
context.YYYYYs.ToArray().OrderBy(x => x.Name)

DBMS の照合順序などの関係により、
凊理される堎所によっお、゜ヌトOrderBy順が異なるためである。

移行メモ誀字: 元ペヌゞの OrberBy は OrderBy の誀蚘。
本文䞭の蚘述も䜵せお修正した。

補足この指摘は重芁: これは性胜ではなく正しさの問題であり、
珟圚も完党に成立する。

  • DB 偎: 照合順序䟋 Japanese_XJIS_100_CI_ASに埓う
    → 倧文字小文字を区別しない、党角半角を区別しないなど
  • メモリ偎: .NET の StringComparer既定はカルチャ䟝存に埓う

「ペヌゞングは DB 偎、衚瀺順の埮調敎はメモリ偎」のように
゜ヌトの堎所が混圚するず順序が砎綻する。
ペヌゞングSkip/Takeを䌎う堎合は特に臎呜的で、
同じ行が 2 ペヌゞに出たり欠けたりする。

トラッキングしない

AsNoTracking() メ゜ッドで Collection を取埗するず、
Entity Statesのトラッキングをしなくなる。

var YYYYYs = context.YYYYYs.AsNoTracking().ToArray();

これにより、䜿甚するメモリ量を削枛できる。

補足: メモリだけでなく、倉曎远跡のためのスナップショット䜜成が
省かれるため CPU も削枛でき、参照専甚のク゚リでは䜓感差が出る。
ただし、AsNoTracking() で取埗した゚ンティティを Update() するず
党列が曎新察象になる点に泚意
Entity Framework参照。
EF Core では QueryTrackingBehavior.NoTracking で既定倀を倉曎するこずもできる。

コヌドファヌスト云々

  • クラス名(+s) がテヌブル名にマップされる。

  • プロパティ名がカラム名にマップされる。

  • 䞻キヌは id or クラス名 + id がデフォルト。

  • 参考

マむグレヌション

コヌドファヌストのデヌタモデル クラスの倉曎をもずに、
既存のデヌタを残したたたデヌタベヌスのテヌブルを倉曎する機胜。

芏玄

コヌドファヌストでは芏玄に基づいお Entity ず Database を玐付ける。

属性

属性による芏玄。

項番 属性名 説明
1 Table Entity ず Table 間のマッピング
2 Column Entity の Property ず Table の Column 間のマッピング
3 ComplexType Entity の耇数の Property(Properties) ず Table 間のマッピング
ComplexType の耇数の Property(Properties) は、別の Table に切り出される。
4 Key Entity の Property を察応する Table の PrimaryKey に蚭定する。
5 Required Entity の Property に察応する Table の Column を NOT NULL に蚭定する。
MVC の ModelMetadata ずしお怜蚌凊理に䜿甚される。
6 MaxLength Entity の Property に察応する Table の Column のデヌタ長を蚭定する。
MVC の ModelMetadata ずしお怜蚌凊理に䜿甚される。
7 Index Entity の Property に察応する Table の Column を䜿甚した非クラスタ化・むンデックスを䜜成する。
8 NoMapped Entity の Property を Database にマップしない。

その他、DbContext を継承した Context のコンストラクタで接続文字列を決定できる。

移行メモ正誀: 項番 8 の属性名は NoMapped ではなく NotMapped が正しい。
たた、EF Core では [Index] 属性は
䞀時期廃止されたのち EF Core 5 で埩掻しおおり
[Index(nameof(Prop))] ずしおクラスに付䞎、
EF6 の曞き方プロパティに付䞎ずは異なる。
ComplexType は EF Core では長く未サポヌトで、
EF Core 8 で耇合型Complex Typesずしお再導入された。

Fluent API

Fluent API による芏玄。

補足属性ず Fluent API の䜿い分け: 䞡方䜿える堎合、
Fluent API が優先される。
属性ぱンティティ クラスに氞続化の知識を持ち蟌むため、
ドメむン モデルを玔粋に保ちたい堎合は
IEntityTypeConfiguration<T> に分離するのが定石である。

ナビゲヌション・プロパティ

゚ンティティ間の関連ア゜シ゚ヌションを衚す。

  • x 察䞀は、オブゞェクト参照を䜿甚。
  • x 察倚は、ICollection<T> を䜿甚。

補足遅延読み蟌みの既定が違う: EF6 は
ナビゲヌション プロパティを virtual にするず遅延読み蟌みが既定で有効だったが、
EF Core では既定で無効である
Microsoft.EntityFrameworkCore.Proxies を導入しお
UseLazyLoadingProxies() を呌ぶず有効化できる。

遅延読み蟌みは N+1 問題の䞻芁因であるため、
EF Core の既定明瀺的な Includeのほうが安党偎に倒れおいる。

批刀云々

  • 性胜ず柔軟性が重芖される゚ンタヌプラむズの領域では、䜿い難いずの批刀も倚い暡様。

  • ツヌル等のスタンドアロンのプログラム、情報系システムなどの EUC による
    RAD 開発などにはマッチする可胜性もある。

  • たた、ADO.NET は枯れた技術であるのに察し、Entity Framework は進化の䜙地がある。

信任投祚

補足信任投祚の顛末: 2008 幎の "Vote of No Confidence" は、
EF v1 が「氞続化非䟝存Persistence Ignoranceを欠く」
「モデル駆動が過剰」ずいった点を批刀したもの。
その埌、EF 4.1 の Code First ず POCO サポヌトによっお
批刀の䞭心的な論点はほが解消された。
歎史的経緯ずしお読むべき節である。

ORMの問題

気付き

Entity Framework をキャンセルしたASP.NET Identityの
UserStoreを実装しお「ORM の問題だな。」ず思った点は、

プログラムの

  • むンタヌフェむスずなっおいる芪子階局のあるオブゞェクト・モデルず、
  • ストレヌゞずの同期凊理セヌブ・ロヌドのタむミングなどが、

実装者にずっお「難しい。」っおトコロではないかず思う。

背景

  • 難しさの背景は、

    • 自分でUserStoreを実装しおいおもこの同期は難しい。

      • 同期凊理の仕様を決める必芁がある。
      • 同期凊理の仕様を思い出し、
        凊理党䜓ずの繋がりを理解する必芁がある。
    • ORM プロダクトでブラックボックス化した堎合、

      • 同期凊理の仕様を決める必芁は無いが、
      • 同期凊理の仕様を調べたり、デバッガでリバヌスしお
        Entity Framework の調査、
        凊理党䜓ずの繋がりを理解する必芁がある。

    等ず蚀った点だず思う。

  • ※

    • UserStoreは、Memory モヌドず DBMS モヌドを凊理するので、
      Memory モヌドの実装の埌、DBMS モヌドを実装しようずしたタむミングで
      この難しさに気付く。

    • オブゞェクトを操䜜したタむミングで盎ちに同期される仕様にすれば、
      問題はなくなるが、実際は、性胜云々に曞いたように、
      性胜を考慮しお適切なタむミングに同期する必芁がある。

補足この難しさの正䜓: ここで述べられおいるのは、
オブゞェクト グラフの氞続化タむミングずいう、
ORM の本質的な難所である。
EF の SaveChanges() や JPA の flush が
「い぀、どこたでを曞き蟌むのか」を理解しにくいのず同根で、
Unit of Work パタヌンが抱える固有の耇雑さず蚀える。

実務での緩和策は、

  • 集玄Aggregateの境界を小さく保぀
    芪子階局を深くしない
  • DbContext の寿呜を短くする
    ASP.NET Core の Scopedリク゚スト単䜍が既定なのはこのため
  • 読み取りず曞き蟌みでモデルを分けるCQRS 的な割り切り

あたりになる。

゚ンプラ領域でのミスマッチ

基幹系システムでは以䞋の理由でミスマッチず刀断されるこずが倚い。

むンピヌダンス・ミスマッチ

抂念モデルに察しおプログラミングを採甚しおいる。

  • 倖郚スキヌマを䜿甚できないため、論理デヌタ独立性が無い。
  • 抂念スキヌマのデヌタ構造を䜿甚しおプログラミングを行う必芁がある。

スキヌマ構造の倉曎

  • DBMS のスキヌマからモデルEDMを生成する方法を採甚しおいる堎合、
    スキヌマの構造が倉わった堎合、モデルEDMの䜜り盎しが発生する。

  • 生成されたモデルEDMをカスタマむズしおいた堎合、
    䜜り盎しにより、カスタマむズが砎棄されおしたう可胜性がある。

    • カスタマむズがなければ、抂念スキヌマ構造の倉曎を
      モデルEDMに同期し、倉曎に迅速に察応できるずも蚀える。
    • しかし、論理デヌタ独立性が無いため、プログラムの倉曎は必芁になる。
  • RAD 開発ツヌルに特有の、保守性の悪さがある。

補足EDMX が無くなったこずによる倉化: EF Core には EDMX が無く、
リバヌス ゚ンゞニアリングは dotnet ef dbcontext scaffold による
C# コヌド生成である。
生成先を partial class ずしお扱い、カスタマむズを別ファむルに眮けば、
再 scaffold でカスタマむズが倱われる問題は緩和できる。
ただし「論理デヌタ独立性が無い」ずいう指摘そのものは、
゚ンティティテヌブルずいう察応を採る限り珟圚も成立する。

察凊ずしおは、

  • DB 偎にビュヌを䜜り、それを゚ンティティにマップする
    EF Core の ToView()。倖郚スキヌマに盞圓する局を DB 偎で持぀
  • 読み取り専甚の DTO ぞ盎接射圱するSelect で必芁な圢に敎圢

ずいった圢で、倖郚スキヌマ的な局を別途蚭けるこずになる。

内郚実装ずその動䜜がブラックボックス

SQL が、LINQ to Entity の゚ンゞンに生成される圢であり、
たた、内郚実装ずその動䜜がブラックボックスになっおいるため※1
それらが明確にならないず蚭蚈、チュヌニング、問題分析などが困難。

埓っお特に日本の゚ンタヌプラむズ・アプリケヌションでは敬遠されおいる。
これは、Java の Java8 で JPA で Hibernate で Jinq が敬遠されるのず ≒。

最新の動向

゚ンプラ界隈でのEntity Framework離れ進んでたすね。

https://www.osscons.jp/jowlrb9pr-537/

NoSQL甚のEntity Frameworkが流行っおいない。

  • Entity Framework、RDB より NoSQL のほうがマッチしそう。
  • しかし、長々、NoSQL 甚の Entity Framework プロバむダがリリヌスされなかった。
  • 2018 幎に EF コアが SQL デヌタベヌスず NoSQL デヌタベヌスを統䞀したらしい。
  • ...しかし、たったく流行っおいない感。

補足最新化Cosmos DB プロバむダ: ここで蚀及されおいるのは
EF Core の Azure Cosmos DB プロバむダEF Core 3.0 で正匏提䟛である。
珟圚も提䟛・改善が続いおいるが、

  • リレヌショナル固有の機胜結合、マむグレヌション等は䜿えない
  • Cosmos DB 偎の APIパヌティション キヌ、RU 消費を意識する必芁があり、
    結局「抜象化できおいない」

ため、NoSQL では各サヌビスの SDK を盎接䜿うのが䞻流のたたである。
「たったく流行っおいない感」ずいう芳察は、珟圚も抂ね劥圓ず蚀える。

補足珟圚の総括: 本ペヌゞの懞念のうち、

懞念 珟圚
䞀括曎新ができない 解消ExecuteUpdate / ExecuteDelete
遅延読み蟌みによる N+1 緩和EF Core は既定で無効
EDMX の䜜り盎し 解消EDMX 自䜓が無い
信任投祚の論点POCO / 氞続化非䟝存 解消Code First
発行 SQL が芋えない 緩和ログ・ク゚リ ストア
論理デヌタ独立性が無い 残るビュヌや DTO で別途察凊
耇雑な集蚈・動的ク゚リの衚珟力 残る生 SQL ずの䜵甚が前提

結論ずしお、珟圚は排他ではなく䜵甚が定石である。
倧半の CRUD は EF Core、性胜が芁る箇所ず耇雑な参照系は
Dapperか生の ADO.NET、ずいう構成が広く採られおいる
ADO.NET vs ORM (Entity Framework, Dapper)。


Tags: 移行, .NET開発, デヌタアクセス, ADO.NET, Entity Framework, 性胜

⚠ **GitHub.com Fallback** ⚠