n層アーキテクチャ:ビジネスオブジェクトを保管するのに最適な場所は?
-
18-09-2019 - |
質問
3 層アーキテクチャ (UI、ビジネス、データ) があるとします。通常、データ アクセス オブジェクトを保持するために「Model」または「Common」という 4 番目のプロジェクトを作成し、他の各プロジェクトがこのプロジェクトを使用します。
現在、私はデータ アクセス オブジェクトの一部に、データ プロジェクトへのアクセスを必要とする Save() などのメソッドがあるプロジェクトに取り組んでいます。したがって、Data プロジェクトで Model/Common プロジェクトを使用しようとすると、循環参照が発生します。
このシナリオでは、データ アクセス オブジェクトを保管するのに最適な場所はどこでしょうか?データ プロジェクト自体内に保持することもできますが、データ アクセス オブジェクトについて知る必要がある UI プロジェクトはデータ レイヤーにアクセスする必要があり、これは良くありません。
解決
これが私のプロジェクトにあるものです。
1.) アプリケーション.インフラストラクチャ
- すべてのビジネス オブジェクトの基本クラス、ビジネス オブジェクト コレクション、データ アクセス クラス、および拡張メソッドとしてのカスタム属性とユーティリティ、汎用検証フレームワーク。これにより、最終的な .net アプリケーションの全体的な動作構成が決まります。
2.) アプリケーション.データモデル
- データベースの型付きデータセット。
- TableAdapters は、トランザクションや必要になる可能性のあるその他の機能を組み込むために拡張されました。
3.) アプリケーション.データアクセス
- データ アクセス クラス。
- 基礎となる型付きデータセットを使用してデータベース アクションがクエリされる実際の場所。
4.) アプリケーション.ドメインオブジェクト
- ビジネス オブジェクトとビジネス オブジェクト コレクション。
- 列挙型。
5.) アプリケーション.ビジネスレイヤー
- プレゼンテーション層からアクセスできるマネージャー クラスを提供します。
- HttpHandlers。
- 私自身のページ基本クラス。
- さらに多くのものはここにあります..
6.) アプリケーション.Webクライアント または アプリケーション.Windowsクライアント
- 私のプレゼンテーション層
- Application.BusinessLayer および Application.BusinessObjects から参照を取得します。
Application.BusinessObjects はアプリケーション全体で使用され、必要に応じてすべてのレイヤーに移動します (Application.DataModel と Application.Infrastructor を除く)。
私のクエリはすべて Application.DataModel のみで定義されています。
Application.DataAccess は、データ アクセス操作の一部として Business オブジェクトを返すか取得します。ビジネス オブジェクトは、リフレクション属性を使用して作成されます。各ビジネス オブジェクトは、データベース内のターゲット テーブルへの属性マッピングでマークされ、ビジネス オブジェクト内のプロパティは、それぞれのデータベース テーブルのターゲット列への属性マッピングでマークされます。
私の検証フレームワークでは、指定された ValidationAttribute を利用して各フィールドを検証できます。
私のフレームワークは属性を多用して、マッピングや検証などの面倒なタスクのほとんどを自動化します。フレームワークの新しい側面として新しい機能を追加することもできます。
私のアプリケーションでは、サンプル ビジネス オブジェクトは次のようになります。
ユーザー.cs
[TableMapping("Users")]
public class User : EntityBase
{
#region Constructor(s)
public AppUser()
{
BookCollection = new BookCollection();
}
#endregion
#region Properties
#region Default Properties - Direct Field Mapping using DataFieldMappingAttribute
private System.Int32 _UserId;
private System.String _FirstName;
private System.String _LastName;
private System.String _UserName;
private System.Boolean _IsActive;
[DataFieldMapping("UserID")]
[DataObjectFieldAttribute(true, true, false)]
[NotNullOrEmpty(Message = "UserID From Users Table Is Required.")]
public override int Id
{
get
{
return _UserId;
}
set
{
_UserId = value;
}
}
[DataFieldMapping("UserName")]
[Searchable]
[NotNullOrEmpty(Message = "Username Is Required.")]
public string UserName
{
get
{
return _UserName;
}
set
{
_UserName = value;
}
}
[DataFieldMapping("FirstName")]
[Searchable]
public string FirstName
{
get
{
return _FirstName;
}
set
{
_FirstName = value;
}
}
[DataFieldMapping("LastName")]
[Searchable]
public string LastName
{
get
{
return _LastName;
}
set
{
_LastName = value;
}
}
[DataFieldMapping("IsActive")]
public bool IsActive
{
get
{
return _IsActive;
}
set
{
_IsActive = value;
}
}
#region One-To-Many Mappings
public BookCollection Books { get; set; }
#endregion
#region Derived Properties
public string FullName { get { return this.FirstName + " " + this.LastName; } }
#endregion
#endregion
public override bool Validate()
{
bool baseValid = base.Validate();
bool localValid = Books.Validate();
return baseValid && localValid;
}
}
ブックコレクション.cs
/// <summary>
/// The BookCollection class is designed to work with lists of instances of Book.
/// </summary>
public class BookCollection : EntityCollectionBase<Book>
{
/// <summary>
/// Initializes a new instance of the BookCollection class.
/// </summary>
public BookCollection()
{
}
/// <summary>
/// Initializes a new instance of the BookCollection class.
/// </summary>
public BookCollection (IList<Book> initialList)
: base(initialList)
{
}
}
他のヒント
私はあなたのn層がかなり右持っていないと思います。あなたはより多くの2層システムを構築しているように聞こえます。
は、実際の3層プロジェクトでは、唯一のあなたのデータ層は、データベースに話をすることが許可されています。あなたの「モデル」または「共通」のプロジェクトであることを持っています。これらのプロジェクトは、<全角> のあなたのデータ層です。しかし、ここであなたがオフに向きを変えることは、ののみのビジネス層は、彼らに話をさせるべきであるということです。プレゼンテーションのコードは、すべてのデータ層のプロジェクトに話をさせてはなりません。
N層は、あなたが3つ以上の「ティア」を持っているときにしていますが、同じ原理プライヤー:各階層にのみ使用する方法を知っている(とのみへの参照を必要とする)1つ下、次にためのAPIを提供しますそれ以上の層。私自身のプロジェクトでは、私はあなたの典型的なプレゼンテーション、ビジネス、およびデータ層を取り、ビジネスとデータの間に第4回「翻訳」ティアを提供しています。この方法では、データ層は、データセット、データテーブル、およびデータローのようなジェネリック型を返すことができ、そしてビジネス層は、ののみのは、強く型付けされたビジネス・オブジェクトの観点で作業する必要があります。翻訳層は、の唯一のは、一般的なデータオブジェクトと強く型付けされたオブジェクト間で変換します。この方法では、伝統的な層のいずれかへの変更は、別の変更を必要とする可能性が低います。
リレーショナル バックエンドを使用している場合、データ レイヤーは行と列の観点から情報を格納する必要があります (必要に応じて、型指定された DataSet を使用することもできます)。「ビジネスオブジェクト」はありません。
ビジネス層では「ビジネス オブジェクト」を使用する必要があります。BusinessObjects プロジェクトへの参照を含めることができます。
要約すれば:
- UI には Business および BusinessObjects への参照があります
- ビジネスには BusinessObjects と Data への参照があります
お役に立てれば。
私は、BusinessObjectsプロジェクト、マッピング(ORM)と対応するDATAACCESSをそれらにCRUD操作をさらすサービス(ともGETALLのような他の人)などを格納し、サーバ側を持っています。
私が作成し、それをモデル事業に何をしたいのインターフェース、およびデータ層でその定義を実装することをお勧め。そのように、すべての3(4?)のプロジェクトは、それが実装されていますかを知らなくても、その定義を使用することができます。
私の意見では、唯一のビジネス層はデータアクセスオブジェクトの知識を持っている必要があります。独自のビジネスルールとロジックを適用しながら、上記のUI層にダムオブジェクト(例えば、データ転送オブジェクト)を返し、その後、データ操作のためにそれらを使用する必要があります。
あなたは自動的にデータとビジネス・オブジェクト間のマッピングするために AutoMapper のようないくつかのものを使用することができます。
それは本当にあなたがMVC(フロントコントローラパターン)を使用している場合、モデルは、我々が使用するアプリケーションが動作する時にデータのドメイン固有の表現(これで、一般的にORMヘルプ)データプロジェクトです、パターンに依存しますこのクラスのために。
データアクセスが別のプロジェクトでは、リポジトリの形になるようにモデルは、データアクセスオブジェクトではありません。ビジネスルール、最終的にはWebプロジェクトのためのサービス。このアプローチではData.dllは、すべてのプロジェクトで参照されています。 モデルは遍在のようなものです。
DATA(Domain Model) -> REPOSITORY(Data Access) -> SERVICE(Business Rules) -> WEB