2

현재 코드 액세스가 데이터 액세스 레이어로 프로토 타입으로 ASP .NET MVC 3 웹 응용 프로그램을 개발 중입니다. 지금 당장 나는 코드를 어디에 넣을 지 혼란 스럽다.데이터베이스에 액세스하는 메소드를 두는 곳

고객 및 수업 프로젝트 클래스가 있습니다. 프로젝트는 고객에게 네비게이션 속성을 제공합니다.

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; } 
} 

나는 두 가지 클래스를 codefirst를 사용하여 데이터 액세스에 사용합니다.

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

가 나는 직접 내 MVC보기에 이러한 데이터 액세스 클래스를 사용하지 에 가장 좋은 방법은 있다고 배웠습니다 - 그래서 나는 단일 고객에 대한 뷰 모델 (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(); 
    } 

... 그러나 서비스 클래스와 고객 클래스는 데이터 액세스가 가능한 두 개의 장소가있다.

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

을 ...하지만 그때 컨트롤러에서 호출했다 :

나는 또한 내 ServiceClass에이 코드를 넣을 수

 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); 
     } 

... 나는이 부를 수 메서드를 내 고객 클래스의 getter에서 내 서비스 클래스에서 가져옵니다.

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

설명 된 방법의 모든 일을하고 나에게 정확한 결과를 제공 - 하지만 내가 올바른 방법으로 수행 할 - 당신이 그것을 할 것 어떻게 - 또는 나는 완전히 트랙 떨어져입니다 ;-) ?

감사합니다.

+0

나는 일반적으로 OK, 더 나은 인터페이스'ICustomerService' (CustomerService는 인터페이스를 구현할 것이다)를 만들고 DI와 함께이 인터페이스를 사용한다고 말하고 싶다. gazillion 테이블을 가지고 있으면 성가신 일이 아닌 non-generic 저장소 접근법을 사용하고 있지만 더 작은 DB의 경우 관리하기 쉽고 디버깅하기가 쉽습니다.)'GetProjectCount (int customerId)'를 인터페이스의 메소드로 사용합니다. –

+0

정확히 이해할 수 있도록 명확히하기 위해 : CustomerService에서 CustomerService 구현 - CustomerService에서 GetProjectCount 메서드를 구현 한 다음 (DbContext?)를 주입 하시겠습니까? 그런 다음 데이터를 가져 오는 내 컨트롤러에서 GetProjectCount를 사용하십시오. – Jetro223

+0

전체'ICustomerService '를 주입하십시오. Autofac에서는 다음과 같이 보입니다 ('Global.asax'에서) : var builder = new ContainerBuilder(); builder.Register (서비스 => 새 CustomerService()). (). InstancePerHttpRequest(); ... '. 그런 다음 컨트롤러의 생성자에서 매개 변수로'ICustomerService'를 전달하고 컨트롤러의 멤버에게 할당 한 다음 저장소를 사용할 수 있습니다. :) 그렇습니다. 그러면 멤버를 사용하여 컨트롤러에서 GetProjectCount를 호출 할 수 있습니다. –

답변

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. 
} 

디그 레션 (Digression) - 예를 들어 데이터베이스 컨텍스트 팩토리가 그 것처럼 보일 수 있습니다.나중에 데이터베이스 연결을 변경

같은 쉬운 설치는 선택의 IoC 컨테이너와 함께 작동 물론
public static ContextFactory 
{ 
    public static YourContext GetDBContext() 
    { 
     return new YourContext(); 
    }   
} 

, 광산이이 Global.asax에 Application_Start 간다 웹 애플 리케이션을위한 Autofac입니다 :

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)); 

의존성 주입은 나중에 모의 도우미 중 하나를 사용하여 데이터베이스 액세스를 모의 할 수 있으므로 (예 : 준비된 항목 목록) 컨트롤러를 나중에 테스트하는 것이 더 쉽습니다.

그러나 대부분의 리포지토리 메소드가 비슷하다면 코드를 반복 할 필요가 없으므로 사용자의 요구에 더 적합한 general solution (it's for database-first, but can be applied to code-first too)을 더보고 싶을 수 있습니다. 코드가 좀 더 복잡해 보일 수 있습니다. :)

+0

적절한 SoC, IoC, 여기 모두 있습니다. 이것은 내가 잘 구축하는 방식이며, 아직 나를 실패하지 않았습니다. 교차 절단 문제가있는 기능을 추가해야하는 경우 몇 번이나 내 베이컨을 저장했습니다. –

+0

의견에 진술 해 주시고 정확한 설명을 보내 주셔서 감사합니다. 설명대로 해보겠습니다. – Jetro223

관련 문제