2

私は現在、データ アクセス レイヤーとして Code First を使用して、ASP .NET MVC 3 Web アプリケーションをプロトタイプとして開発しています。今、私は自分のコードをどこに置くべきか少し混乱しています。

クラス Customer とクラス プロジェクトがあります。プロジェクトには、顧客へのナビゲーション プロパティがあります。

public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class Project
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual Customer Customer { get; set; }
}

これら 2 つのクラスを使用して、codefirst によるデータ アクセスを行います。

public class MyContext : DbContext
{
    public DbSet<Customer> Customers { get; set; }
    public DbSet<Project> Projects { get; set; }
}

これらのデータ アクセス クラスを MVC ビューで直接使用しないことがベスト プラクティスであることを学びました。そのため、単一の Customer 用に ViewModel (CustomerListModel) と DTO を作成しました。

public class CustomerDto
{        
    public int Id { get; set; }
    public string Name { get; set; }
    public int ProjectCount { get; set; } <== this property is in question
}

public class CustomerListModel
{
    public List<CustomerDto> Customers;
}

私のコントローラでは、実際のデータ アクセスを行う (サービス) クラスから顧客を取得しています。

public class CustomerService : IDisposable
{
    private MyContext db;
    public CustomerService()
    {
        db = new MyContext();
    }

    public IEnumerable<Customer> GetAllCustomers()
    {
        return db.Customers.ToList<Customer>();
    }
}

コントローラーで、すべての顧客を取得するメソッドを呼び出します。

    public ViewResult Index()
    {
        //Mapper.CreateMap<Customer, CustomerDto>();

        var customerList = new List<CustomerDto>();
        foreach (var customer in rep.GetAllCustomers())
        {
            var cust = new CustomerDto();
            cust.Id = customer.Id;
            cust.Name = customer.Name;
            cust.Rate = customer.Rate;
==> cust.ProjectCount = customer.ProjectCount; <=====
            customerList.Add(cust);
        }

        var viewModel = new CustomerListModel()
        {                
            Customers = customerList //Mapper.Map<IEnumerable<Customer>, List<CustomerDto>>(rep.GetAllCustomers())
        };
        return View(viewModel);            
    }

私が求めているのは、たとえば単一の顧客の ProjectCount をどこに置くかです。私はそれを顧客クラスに入れることができました

    public int ProjectCount
    {
       var db = new MyContext();
       return db.Projects.Where(x => x.Customer.Id == this.Id).Count();
    }

...しかし、データにアクセスできる場所が 2 つあります。サービス クラスと顧客クラスです。

このコードを ServiceClass に入れることもできます。

    public int GetProjectCount(Customer customer)
    {
        return db.Projects.Where(x => x.Customer.Id == customer.Id).Count();
    }

...しかし、コントローラーから呼び出す必要がありました。

        foreach (var customer in rep.GetAllCustomers())
        {
            var cust = new CustomerDto();
            cust.Id = customer.Id;
            cust.Name = customer.Name;
            cust.Rate = customer.Rate;
            cust.ProjectCount = rep.GetProjectCount(customer); <==
            customerList.Add(cust);
        }

...顧客クラスのゲッターからサービス クラスからこのメソッドを呼び出すこともできます。

    public int ProjectCount
    {
        get
        {
            return new CustomerService().GetProjectCount(this);
        }
    }

説明されているすべてのアプローチが機能し、正しい結果が得られます-しかし、私は正しい方法でそれを行いたいです-どのようにそれを行いますか-または私は完全に軌道から外れています;-)?

ありがとうございました!

4

1 に答える 1

3

以下は、私がコメントに書いたことを要約するための私の見解です。それが「行くべき道」であるかどうかはわかりませんが、実行可能な解決策だと思います.

したがって、非汎用アプローチを使用している場合、(前述のように) 簡単で、テーブルの少ない小さなデータベースの管理とデバッグが簡単な場合は、次のように実行できます。

public interface ICustomerService
{
    IEnumerable<Customer> GetAllCustomers();
    // and other methods you'd like to use
}

public sealed class CustomerService : ICustomerService
{
    private YourContext context = new YourContext();
    // or, alternatively, even something along these lines
    private YourContext context;
    public CustomerService()
    {
        context = ContextFactory.GetDBContext();
    }
    //----

    public IEnumerable<Customer> GetAllCustomers()
    {
         // here goes the implementation
    }
}

public class YourController : Controller
{
    private ICustomerService customerService;
    public YourController(ICustomerService service)
    {
          customerService = service;
    }
    // and now you can call customerService.GetAllCustomers() or whatever other methods you put in the interface. 
}

余談 - データベース コンテキスト ファクトリは、たとえば後でデータベース接続を変更する場合に備えて、次のようになります。

public static ContextFactory
{
    public static YourContext GetDBContext()
    {
         return new YourContext();
    }        
}

もちろん、このような簡単なセットアップは、任意の IoC コンテナーで動作しますApplication_Start

var builder = new ContainerBuilder();
    builder.Register(service => new CustomerService()).As<ICustomerService>().InstancePerHttpRequest();
    builder.RegisterControllers(typeof(MvcApplication).Assembly);
    var container = builder.Build();
    DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

多くのモック ヘルパーの 1 つを使用して、何でも (準備されたアイテムのリストなど) データベース アクセスをモックできるため、依存性注入により、後でコントローラーをテストすることが容易になります。

ただし、ほとんどのリポジトリのメソッドが似ている場合は、ニーズにより適した、より一般的なソリューション (データベース優先ですが、コード優先にも適用できます)を検討することをお勧めします。コードを繰り返す必要はありませんが、コードが少し複雑に見えるかもしれません。:)

于 2012-05-11T12:51:44.420 に答える