4

これは、ここからの私の質問のフォローアップです。

まず、プロジェクトでDDDを使用していません。

3つのレイヤーを持つWCFサービスがあります。

  • サービスレイヤー(操作のみを保持し、BLメソッドを呼び出します)
  • すべてのビジネスロジッククラスとメソッドを保持するビジネスロジックレイヤー
  • DbContext (LINQ-TO-EF)およびPOCOエンティティを保持するデータアクセス層

WCFサービスはDTOオブジェクトを返す必要があり、POCOエンティティをDTOに変換する「Translator」クラスを配置するのに最適な場所を見つけるのに苦労しています。

これには2つのオプションがありました。

方法A

ビジネスロジックメソッドがエンティティをサービスレイヤーに返すようにします。サービスレイヤーには、エンティティをDTOに変換するトランスレータークラスが含まれています。

長所:

  • ビジネスロジックレイヤーは、必要なことを実行します-検証とCRUD操作
  • ビジネスロジック層は、DTOについてまったく知る必要はありません

短所:

  • サービス層は、ビジネスロジック層からエンティティを受け取るため、「データアクセス層」アセンブリへの参照を含める必要があります。これは、サービス層がBL層のみを参照する必要があり、BL層がDALのみを参照する必要があるという3層の概念を破っているようです。
  • これは最悪の問題です。トランスレータクラスはエンティティオブジェクトからDTOを作成する必要があります。DbContextが破棄された後、BLからエンティティオブジェクトを受け取るため、「Include」拡張機能がロードされていないものにはアクセスできません。つまり、BLメソッドは、DTOを作成するためにトランスレータが必要とするすべてのものとともに、エンティティをサービスレイヤーに戻す必要があります。BLはトランスレータが何を必要としているかを知る必要があるため、これは問題です。次に、データベースから多くの不要なデータをフェッチします。(おそらく、トランスレータは、フィールドの1つが「注文の総数」である「UserDto」オブジェクトを返す必要があります。「Count()」を作成するためだけに、データベースからすべての注文をフェッチする必要があるのはなぜですか。

方法B

エンティティオブジェクトからDTOに変換する「Translator」クラスを「ビジネスロジックレイヤー」自体に配置します。このメカニズムでは、BLメソッドはすでにDTOを返します。

長所:

  • BLメソッドはBLコードを実行してから、「translate_to_dto」適切なメッセージを呼び出して、結果をDTOに変換して返します。これはすべて「DbContext」内で実行されます。つまり、トランスレータクラスを呼び出してエンティティを変換する場合でも、子オブジェクトにアクセスでき、「Include」を呼び出す必要はありません。これは、DTOの作成に必要なデータのみがデータベースからフェッチされることを意味します。

短所:

  • これで、「ビジネスロジック層」にある「translator」クラスがDTOについて知る必要がありますが、DTOについてのみ知るのはサービス層の責任です。
  • BLの各メソッドは、純粋なBL(有効性チェック、CRUD操作など)を実行し、さらにDTOを返すためにtranslatorメソッドを呼び出します。これは、(BL内の)メソッドが1つの特定のことだけを実行する必要があるという「単一責任ルール」に違反します。

'Entity ==> DTO'変換を実行するのに適切な場所を教えてもらえますか?

[更新-例を追加]

ビジネスロジック層には、次のようなBLメソッドを持つUserManagerというマネージャークラスがあります。

public UserTasksDto     GetUserInfoWithTasks(Guid userId)
{
    if (userId == Guid.Empty)
        throw new ArgumentException("User ID cannot be empty");

    using (IMyDBEntities entities = _contextFactory.GetContext())
    {
        // Get POCO Object from DbContext
        User user = entities.Users.Find(userId);
        if (user == null)
            throw new EntityNotFoundException("User was not found in the database");

        if (user.Tasks.Count() == 0)
            throw new Exception("User does not have any tasks !");

        // Call 'Translator' static method to translate POCO to DTO
        Translator.TranslateUserToUserTasksDto(user);
    }
}

上記のように、BLメソッドは「translator」メソッドを呼び出してPOCOをDTOに変換します。これは「エンティティ」コンテキストで行われるため、翻訳者は引き続きユーザーの「タスク」の子にアクセスできます。

'Translator'メソッドは次のようになります。

class Translator
{
    public static UserTasksDto   TranslateUserToUserTasksDto ( User userPoco )
    {
        UserTasksDto dto = new UserTasksDto
        {
            UserId        = userPoco.Id,
            Username      = userPoco.Username,
            CreationDate  = userPoco.CreationDate,

            // Accessing a related entity, this is why this 'translate' method 
            // needs to be called inside the DbContext, otherwise it will except
            // (or we load all related entities using 'Include' just for the 'Count' purpose)
            Supervisor    = userPoco.Supervisor.Username,    
            NumOfTasks    = userPoco.Tasks.Count(),
            FirstTaskDate = userPoco.Tasks.OrderBy(task => task.Date).Take(1),
        }

        return dto;
    }
}

上記のように、「Translate」メソッドは「User」POCOオブジェクトから「UserTasksDto」を構築します。これは、「User」オブジェクトとその関連エンティティからDTOにいくつかのフィールドをマッピングすることによって行われます。このメソッドがBLメソッドのObjectContextになかった場合、コンテキストなしでエンティティにアクセスしようとしているという例外が発生します。

私の問題が今より明確になることを願っています...

4

2 に答える 2

2

質問ですが、

サービス レイヤーを BL/DAL データ エンティティから独立させる必要がある場合、私の意見では、独立したモデル用の新しい抽象化レイヤー (dll アセンブリ) が必要です。

BL および/または DAL は、エンティティを返すのではなく、この新しいアセンブリからモデル オブジェクトを返します。

サービス レイヤーには、エンティティの DAL への参照は必要ありませんが、新しいモデル アセンブリへの参照は必要です。

これは、ビュー モデルと同様のパターンです。

現在、サービス層の仕事は、モデルを DTO に変換することです (そうすることが選択された場合)。

長所: BL/DAL への依存から解放されます

短所:モデルの抽象化レイヤーが冗長に見える


編集:

ビジネス層から DTO を返すつもりはありませんでした。私が意味したのは、ビジネス ロジックから独立したモデルを返すことでした。これにより、モデルはすべてのレイヤーから本当に独立し、後でそれらと連携するどのレイヤーでも、それらを使用したり、必要な形式に変換したりできます。

たとえば、サービス層にはモデルから DTO へのトランスレータが含まれる場合があり、プレゼンテーション層はそれらをビュー モデルに変換する場合があり、リポジトリはそれらを XML に変換することを選択する場合があります。これで、各レイヤーには独自の Model to X トランスフォーマーがあり、BL には単一の責任しかなく、すべてのレイヤーは DAL エンティティから独立しています。

NB 一部のレイヤーはそれらを直接使用することを選択する場合がありますが、これはあなたの懸念であると思います。そうであれば、BL が DTO/VM を返したかのように動作しますが、これは私の意図ではありませんでした。

これで問題が解決することを願っています...


アップデート:

BL以外のレイヤーは一切書かない開発者だと思ってください。

DAL のエンティティを返しますか。番号。

ライブラリがどのように使用され、どのレイヤーがそれを使用するかについての考えはありますか? 番号。

DAL エンティティの上に新しい抽象化を作成し、これらをライブラリを使用するレイヤーに返します。

したがって、開発者 X がやって来て、あなたのライブラリを使用して ACME WCF サービスを作成した場合、X はあなたのモデル オブジェクトを DTO として使用せず、むしろ X があなたのモデルを使用して DTO を作成することを確信しています。

開発者 Y がやって来て、あなたのライブラリを使用して ACME ASP.NET MVC 3 アプリケーションを作成します。Y はあなたのモデル オブジェクトを VM (ビュー モデル) として使用するのではなく、Y はあなたのモデルを最初に使用して VM を作成すると確信しています。

于 2012-06-20T12:43:50.013 に答える
0

おそらく適切な場所はありませんが、最も論理的な場所はビジネスロジックです。

于 2012-06-20T12:16:03.623 に答える