0

ASP.net で依存性注入を使用して、最初のデータ ドリブン ドメインの開発に取り組んでいます。

たとえば、いくつかのドメイン データ モデルを作成した場合、データ アクセス レイヤーで:

public class Company {
   public Guid CompanyId { get; set; }
   public string Name { get; set; }
}

public class Employee {
   public Guid EmployeeId { get; set; }
   public Guid CompanyId { get; set; }
   public string Name { get; set; }
}

次に、次のようなインターフェイスを開発しました。

public interface ICompanyService {
   IEnumerable<Model.Company> GetCompanies();
   IEnumerable<Model.Employee> GetEmployees();
   IEnumerable<Model.Employee> GetEmployees(Guid companyId);
}

別のモジュールで、Linq to Sql を使用してこのインターフェイスを実装しました。

public class CompanyService : ICompanyService {

    public IEnumerable<Model.Employee> GetEmployees();
    {
        return EmployeeDb
            .OrderBy(e => e.Name)
            .Select(e => e.ToDomainEntity())
            .AsEnumerable();
    }
}

ToDomainEntity() は、基本エンティティ クラスの拡張メソッドとして従業員リポジトリ クラスに実装されます。

public Model.EmployeeToDomainEntity()
{
     return new  Model.Employee {
         EmployeeId = this.EmployeeId,
         CompanyId = this.CompanyId,
         Name = this.Name
     };
}

ここまでは、Mark Seeman の優れた著書「Dependency Injection in .NET」で説明されているパターンに多かれ少なかれ従ってきましたが、すべてうまく機能しています。

ただし、基本モデルを拡張して主要な参照モデルも含めるようにしたいので、ドメインの Employee クラスは次のようになります。

public class Employee {
   public Guid EmployeeId { get; set; }
   public Guid CompanyId { get; set; }
   public Company { get; set; }
   public string Name { get; set; }
}

ToDomainEntity() 関数は次のように拡張されます。

public Model.Employee ToDomainEntity()
{
     return new  Model.Employee {
         EmployeeId = this.EmployeeId,
         CompanyId = this.CompanyId,
         Company = (this.Company == null) ? null : this.Company.ToDomainEntity()
         Name = this.Name
     };
}

これはドメイン モデリングの観点からは「悪い習慣」ではないかと思いますが、私が遭遇した問題は、同じ目的を達成するために特定のビュー モデルを開発する場合にも当てはまると思います。

本質的に、私が遭遇した問題は、データ モデルを作成する速度/効率です。上記の ToDomainEntity() アプローチを使用すると、Linq to Sql は個別の SQL 呼び出しを作成して、各従業員の Company レコードのデータを取得します。これにより、ご想像のとおり、特にデータ ツリーが複雑な場合 (各ノード/ツリーのサブノード)。

データモデルを作成すると「インライン...

public IEnumerable<Model.Employee> GetEmployees();
{
    return EmployeeDb
        .OrderBy(e => e.Name)
        .Select(e => new Model.Employee {
            EmployeeId = e.EmployeeId,
            /* Other field mappings */
            Company = new Model.Company {
               CompanyId = e.Company.CompanyId,
               /* Other field mappings */
            }
        }).AsEnumerable();
}

Linq to SQL は、「内部結合」メソッドをネイティブに使用して会社を従業員に関連付ける、適切でタイトな SQL ステートメントを生成します。

2 つの質問があります。

1) ドメイン クラス オブジェクト内から関連するデータ クラスを参照することは「悪い習慣」と見なされますか?

2) これが事実で、目的のために特定のビュー モデルが作成されている場合、式ツリーを構築するためにインライン割り当てブロックを作成することに頼ることなく、使用してモデルを設定する正しい方法は何ですか?

ヘルプ/アドバイスをいただければ幸いです。

4

2 に答える 2

1

この問題は、データ層エンティティとドメイン層エンティティの両方があり、2 つの間のマッピングが必要なために発生します。これを機能させることはできますが、すでに経験しているように、すべてが非常に複雑になります。データとドメインの間のマッピングを作成していますが、パフォーマンス上の理由と、他のビジネス ロジックとプレゼンテーション ロジックが異なるデータを必要とするため、これらの同じエンティティに対してさらに多くのマッピングをすぐに追加する予定です。

唯一の現実的な解決策は、データ エンティティを捨てて、バックエンド ストア (SQL サーバー) に直接シリアル化できる POCO モデル オブジェクトを作成することです。

POCO エンティティは LINQ to SQL で最初からサポートされているものですが、 Entity Framework Code Firstに移行した方がよいと思います。

これを行うと、リポジトリからインターフェイスを公開できIQueryable<T>ます (現在は your repository と呼んでいますICompanyServiceが、より適切な名前は ですICompanyRepository)。これにより、効率的な LINQ クエリを実行できます。クエリ プロバイダーを介して直接クエリを実行する場合、完全なエンティティの読み込みを防ぐことができます。例えば:

from employee in this.repository.GetEmployees()
where employee.Company.Name.StartWith(searchString)
select new 
{
    employee.Name, 
    employee.Company.Location 
};

を使用する場合IQueryable<T>、LINQ to SQL および Entity Framework はこれを非常に効率的な SQL クエリに変換します。この SQL クエリは、データベース内のフィルター処理を使用してデータベースから従業員名と会社の所在地のみを返します (.NET アプリケーションで をGetEmployees()返すときにフィルター処理を行うのと比較してIEnumerable<T>) 。 .

于 2012-07-13T08:14:25.967 に答える
0

Linq2Sql に特定のエンティティを (遅延ロードではなく) プリロードするように指示できDataLoadOptions.LoadWithますエンティティでこれを行うと、CompanyLinq2Sql がデータベースにアクセスして再度フェッチする必要がなくなると思います。

于 2012-07-12T22:03:37.303 に答える