これはほとんど私を夢中にさせています。 EFは、開発において非常に便利な経験をもたらします。
ただし、上位層でEntityモデルを使用する必要がある場合は、常に上位層からDALまたはEntityクラスを保持している下位の層への参照を配置します。状況を可視化しました。
_ +-------------------+
| |
| Presentation |
(This layer is directly referring to DAL, which break the 3-tier architecture rules)
+-------------------+
|
|
|
|
+---------v---------+
| |
| BLL |
(Function that returning Entity Model)
+-------------------+
|
|
|
|
+---------v---------+
| |
| DAL |
(Repo & Entity Model)
+-------------------+
_
BLLでDTOのようなものを実装することは非常に重く、この問題を完全に解決することはできません。したがって、私はそのような層でDTOを実装しようとしないかもしれません。
その間、次の図のように、一部のプロジェクトがこれらの_Entity Model
_を削除する可能性があることがわかりました。それは問題を解決する良い方法ですか?
_ +-------------------+
| |
+------------------+ Presentation |
| | |
| +---------+---------+
| |
| |
| |
| |
+-----v------+ +---------v---------+
| | | |
| Entities <-----------+ BLL |
| | (Function that returning Entity Model)
+-----^------+ +---------+---------+
| |
| |
| |
| |
| +---------v---------+
| | |
+------------------+ DAL |
| (Repositories) |
+-------------------+
_
この設計で問題の一部を解決できますが、開発者はentity.SaveChanges()
を呼び出して、_Presentation Layer
_からエンティティをDBに更新することができます。それはとても危険です。他の開発者が上位層でSaveChanges()
を呼び出せないようにするにはどうすればよいですか?
他の開発者が上位層でsaveChanges()を呼び出さないようにするにはどうすればよいですか?
これを行うための唯一の健全な方法は、レイヤー間の真の分離を強制することであり、これを行うことができる唯一の合理的な方法は、プレゼンテーション/ BLLインターフェースで独自のデータ転送オブジェクト(DTO)のセットを維持することです。 Entity Frameworkを使用します。
何かお見せしましょう。
私の以前の仕事では、Entity Frameworkを使用しましたが、SaveChanges()
を呼び出したり、Entityクラスを参照する以外の目的でDBContext
オブジェクトを使用したことはありません。代わりに、ベアクエリを使用しました。
_using (var context = new CustomerContext())
{
var customer = context.Database.SqlQuery<Customer>(
"SELECT * FROM Customers WHERE CustomerID = {0}", customerID).FirstOrDefault();
}
_
時間が経つにつれて、EFから生成されたDTOの使用をやめ、独自のDTOの作成を開始しました。ベアクエリは、EFが変更追跡などのDTOに組み込むすべての機構を必要とせず、特定のクエリ用に各DTOをカスタマイズできます。
これは、Entity Frameworkが既に行っている多くの作業に取り組んでいるように聞こえますが、いくつかの大きな利点があります。
私の現在の仕事では、この手法を引き継ぎましたが、Entity FrameworkをStack Exchangeが使用するマイクロORMであるDapperに置き換えました。クエリは上記のものとほとんど同じです。私は このツール を使用してエンティティークラスを生成します。
Dapperの良い点は、変更追跡を含むCRUD拡張が含まれていることです。影響を受けるエンティティに対してUpdate()
を呼び出すだけです。違いは、必要に応じて、プレゼンテーションレイヤーからUpdateメソッドを非表示にできることです。 Dapperが使用するIDbConnection
オブジェクトを無視するだけです。