0

Entity Framework를 사용하는 MVC 5 응용 프로그램에 대해 다음 작업 단위 패턴을 설정했습니다. 그들은 모두 같은 dbcontext를 사용하도록 다음과 같이 작업의 단위는 정의 된 모든 REPOS이 있고 하나는 같은 맥락 사용하여 트랜잭션을 조율하는 방법을 저장할 수있다 :이의 예입니다Entity Framework DbContext ASP.NET MVC의 수명 Ninject 사용?

public class UnitOfWork : IUnitOfWork 
{ 
    private readonly ApplicationDbContext _context; 

    public IProductRepository ProductRepository { get; private set; } 
    public ICustomerRepository CustomerRepository { get; private set; } 
    // Other reposistories 

    public UnitOfWork(ApplicationDbContext context) 
    { 
     _context = context; 
     ProductRepository = new ProductRepository(_context); 
     CustomerRepository = new CustomerRepository(_context); 

     // Other reposistories 
    } 

    public void Complete() 
    { 
     _context.SaveChanges(); 
    } 
} 

을 내 repo. repos를 사용하는 이유는 코드 재사용을 위해 다른 컨트롤러 내부에서 쿼리를 복제하지 않기 위해서입니다. 작품의

public class ProductsController : Controller 
{ 

    private readonly IUnitOfWork _unitOfWork; 
    private readonly IFileUploadService _FileUploadService; 

    public ProductsController(IUnitOfWork unitOfWork, 
      IFileUploadService fileUploadService) 
    { 
     _unitOfWork = unitOfWork; 
     _FileUploadService = fileUploadService; 
    } 

    [HttpPost] 
    [ValidateAntiForgeryToken] 
    public ActionResult Create(CreateEditProductViewModel viewModel) 
    { 
      var product = new Product 
      { 
       // Do stuff 
      }; 

      _unitOfWork.ProductRepository.Add(product); 

      // Call file upload service 
      _fileUploadService.Upload(); 

      _unitOfWork.Complete(); 

    } 

} 

이 장치는 내가 사용 모두에 정의의 repos 인 경우 잘 작동을 설정 : 사용 Ninject에 다음과 같이

public class ProductRepository : IProductRepository 
{ 
    private readonly ApplicationDbContext _context; 

    public ProductRepository(ApplicationDbContext context) 
    { 
     _context = context; 
    } 

    public Product GetProduct(int productId) 
    { 
     return _context.Ticket.SingleOrDefault(p => p.Id == productId); 
    } 

    public void Add(Product product) 
    { 
     _context.Product.Add(product); 
    } 

    // Other methods 
} 

나는 내 컨트롤러에서 작업 클래스의 단위를 주입 작업 단위 클래스. 하지만 이제는 서비스 클래스를 사용하여 몇 가지 추가 응용 프로그램 논리를 처리하고 작업 단위가 제어기 조치에서 확약됩니다. 클래스를 다음과 같이 정의하면 컨텍스트의 다른 인스턴스가 사용됩니다.이 경우 서비스 계층이 다른 컨텍스트로 끝나는 트랜잭션을 어떻게 조정할 수 있습니까?

public class FileUploadService : IFileUploadService 
{ 
    private readonly IUnitOfWork _unitOfWork; 

    public FileUploadService(IUnitOfWork unitOfWork) 
    { 
     _unitOfWork = unitOfWork; 
    } 

    public uploadResult Upload() 
    { 
     // Some stuff 
     var uploadedFile = new UploadedFile 
     { 
      //some stuff 
     }; 

     _unitOfWork.UploadedFileRepository.Add(uploadedFile); 
    } 
} 

저는 온라인에서 많은 조사를 해본 결과이 문제를 해결하기위한 실질적인 예를 제공하는 자료를 찾을 수 없습니다. 작업 단위와 repos를 버리고 단순히 엔티티 프레임 워크 dbset을 사용하여 꽤 많은 것을 읽었습니다. 그러나 위에서 설명한 것처럼 repos를 사용하는 목적은 쿼리를 통합하는 것입니다. 제 질문은 서비스 클래스와 작업 단위 (UOW)를 어떻게 조정하는지입니다.

서비스가 동일한 컨텍스트를 사용하여 작업해야하는 리포지토리에 액세스 할 수 있도록하고 컨트롤러 (클라이언트 코드)가 해당 작업을 볼 때 작업을 커밋하도록합니다.

* UPDATE * 내 DI 컨테이너에서

내가 다음 코드를 사용하여 모든 인터페이스를 해결 :

private static IKernel CreateKernel() 
    { 

      RegisterServices(kernel); 

      kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope(); 

      // default binding for everything except unit of work 
      kernel.Bind(x => x.FromAssembliesMatching("*") 
      .SelectAllClasses() 
      .Excluding<UnitOfWork>() 
      .BindDefaultInterface()); 

      return kernel; 

    } 

겠습니까이 경우에도 더 이상 ApplicationDbContext가 생성되어 있는지 확인 라인 kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope();을 추가에게 요청은 IUnitOfWork (ApplicationDbContext)를 모두 필요로하는 여러 컨트롤러 또는 서비스 계층에 도달하게됩니다.

+0

IUnitOfWork를 어디서나 해결하려면 IOC 컨테이너를 사용하십시오. 스코프 또는 라이프 사이클을 적절하게 설정하십시오. https://structuremap.github.io/object-lifecycle/supported-lifecycles/ – mxmissile

+0

@mxmissile 어떻게하면 이것을 할 수 있습니까? – adam78

+0

http://jasonwatmore.com/post/2015/01/28/Unit-of-Work-Repository-Pattern-in-MVC5-with-Fluent-NHibernate-and-Ninject.aspx NHibernate에 대한 것이지만 그 생각. – mxmissile

답변

0

MVC를 사용하는 경우 작업 단위는 웹 요청입니다. 내가 당신이라면 UOW 구현을 버리고 db_Bextext가 Application_BeginRequest에서 인스턴스화되었는지 확인해야합니다. 그런 다음 안전하게 유지하기 위해 HttpContext에 채 웁니다. Application_EndRequest에서 DbContext를 처리합니다.

저장소를 저장소로 옮깁니다.

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] 
public class TransactionAttribute : ActionFilterAttribute 
{ 
    private TransactionScope Transaction { get; set; } 

    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     Transaction = new TransactionScope(TransactionScopeOption.Required); 
    } 

    public override void OnActionExecuted(ActionExecutedContext filterContext) 
    { 
     if (filterContext.Exception == null) 
     { 
      Transaction.Complete(); 
      return; 
     } 

     Transaction.Dispose(); 
    } 
} 

그런 다음 바로 [거래]와 컨트롤러 방법을 태그 할 수 있습니다

나는 이런 TransactionScope에 뭔가를 유지하는 것 [거래] 속성을 만들 것입니다.

나는 여기에서 spitballing 일 뿐이다. 그러나 나는 EF 대신에 NHibernate와 비슷한 것을하고 그것은 나에게 잘 해준다.

+0

저장소를 내 저장소로 이동했는데 어떤 저장소로 이동합니까? – adam78

+0

일반 저장소 <>를 사용하므로 1 개만 보유하고 있지만 모든 리포지토리에서 수행해야하지만 트랜잭션에 앉아 있기 때문에 데이터베이스에 쓰지는 않습니다. – Fran

0

InRequestScope()은 모든 새 웹 요청에서 바인딩 된 유형의 새 인스턴스를 만들고 해당 웹 요청이 끝나면 처분 할 수있는 경우 해당 인스턴스를 삭제합니다.

ApplicationDbContext을 어떻게 UnitOfWork에 전달하는지 잘 모르겠습니다. 나는 당신도이 주사에 Ninject를 사용한다고 가정하고 있습니다. InRequestScope()Bind.To().InRequestScope();을 사용하여 ApplicationDbContext을 묶어야합니다.

이렇게하면 ApplicationDbContext 인스턴스가 요청마다 한 번 만들어지고 끝에 배치됩니다.

또한 InRequestScope은 일회용 유형을위한 것이기 때문에 UnitOfWork 방법의 Dispose 메서드에서도 음원을 릴리스 할 수 있습니다.