2011-01-27 23 views
11

Tôi đã tự hỏi làm thế nào để bạn phạm vi Dbcontexts của bạn trong Entity Framework, do đó bạn không sử dụng một Dbcontext duy nhất cho toàn bộ ứng dụng của bạn. Tôi mới vào Entity Framework và đã đọc hướng dẫn, nhưng tất cả họ đều sử dụng một Dbcontext đơn lẻ làm ví dụ, vì vậy EF là một hộp đen cho tôi ngay bây giờ.Làm thế nào để phạm vi ra Dbcontexts (để ngăn chặn bối cảnh singleton cho toàn bộ ứng dụng)

Hãy nói ví dụ tôi có 3 mô hình:

  • bài
  • tài
  • Comment

Mỗi mô hình có liên quan đến nhau (A bài viết thuộc về dùng, Comment thuộc cho người dùng và bài đăng). Tôi có tạo ra một Dbcontext cho từng cái riêng lẻ không? Nhưng điều đó sẽ không chính xác vì tất cả chúng đều liên quan, hoặc tôi sẽ tạo ra một Dbcontext cho mỗi kịch bản mà tôi cần? Ví dụ: nếu tôi chỉ cần truy vấn Đăng và Nhận xét chứ không phải người dùng thì đó sẽ là PostCommentsContext. Và sau đó chúng tôi sẽ có một người sử dụng PostUserCommentContext ...

+1

Ngoài ra khi bạn sử dụng UnitOfWork với ORM, bạn cần lưu ý rằng nếu cam kết không thành công thì bạn cần một bối cảnh/đơn vị công việc mới http://lavinski.tumblr.com/post/9114111237/object-relational-mapper -exceptions –

Trả lời

7

Giải pháp tốt nhất là sử dụng Đơn vị công việc để bọc bối cảnh dữ liệu, cũng như quản lý thời gian kết nối và cho phép bạn làm việc với nhiều kho lưu trữ (nếu bạn có xu hướng đi xuống đường dẫn đó) .

Tóm tắt thực hiện:

  • Tạo một giao diện (IUnitOfWork) mà thấy nhiều thuộc tính cho DbSet của bạn 's, cũng như một phương pháp duy nhất gọi là Commit
  • Tạo một thực hiện (EntityFrameworkUnitOfWork), thực hiện theo yêu cầu. Cam kết chỉ cần gọi số SaveChanges trên lớp cơ sở (DbContext) và cũng cung cấp một móc nối tốt cho logic phút cuối cùng.
  • điều khiển của bạn chấp nhận một IUnitOfWork, sử dụng DI (tốt nhất) để giải quyết một EntityFrameworkUnitOfWork, với một HTTP bối cảnh scoped đời thiết lập (StructureMap là tốt cho việc này)
  • (không bắt buộc, nhưng khuyến khích) tạo ra một Repository cũng mất IUnitOfWork và làm việc đó thông qua Bộ điều khiển của bạn.

HTH

EDIT - Trong Response to Comments

Oh, làm thế nào bạn có thể làm công việc có liên quan đến việc tạo ra các bản ghi trong nhiều mô hình sau đó? tức là, tạo người dùng mới và bài đăng mới trong cùng một giao dịch.

Với việc sử dụng ASP.NET MVC, bộ điều khiển của bạn nên chấp nhận một IUnitOfWork trong hàm tạo của chúng.

Dưới đây là một ví dụ, dựa trên những gì bạn hỏi

public SomeController : Controller 
{ 
    private IUnitOfWork _unitOfWork; 
    private IUserRepo _userRepo; 
    private IPostRepo _postRepo; 

    public SomeController(IUnitOfWork unitOfWork, IUserRepo userRepo, IPostRepo postRepo) 
    { 
     _unitOfWork = unitOfWork; // use DI to resolve EntityFrameworkUnitOfWork 
     _userRepo = userRepo; 
     _postRepo = postRepo; 
    } 

    [HttpPost] 
    public ActionResult CreateUserAndPost(User user, Post post) 
    { 
     // at this stage, a HTTP request has come in, been resolved to be this Controller 
     // your DI container would then see this Controller needs a IUnitOfWork, as well 
     // as two Repositories. DI smarts will resolve each dependency. 
     // The end result is a single DataContext (wrapped by UoW) shared by all Repos. 
     try 
     { 
     userRepo.Add(user); 
     postRepo.Add(post); 
     // nothing has been sent to DB yet, only two objects in EF graph set to EntityState.Added 
     _unitOfWork.Commit(); // two INSERT's pushed to DB 
     } 
     catch (Exception exc) 
     { 
      ModelState.AddError("UhOh", exc.ToString()); 
     } 
    } 
} 

Và thêm một câu hỏi, những gì hiện các HTTP bối cảnh scoped đời làm gì?

Đối tượng trong DI-talk có các cài đặt quản lý phạm vi bao gồm cho mỗi thread, mỗi phiên, theo yêu cầu http, singleton vv

HTTP bối cảnh scoped là cài đặt khuyến khích cho các ứng dụng web. Nó có nghĩa là "mới lên một bối cảnh khi một yêu cầu HTTP đi vào, và loại bỏ nó khi yêu cầu kết thúc".

+0

Tôi hiện đang sử dụng mẫu kho lưu trữ. Tuy nhiên, với mẫu Unit of Work, các kho lưu trữ có nằm trong UoW không? Điều gì sẽ xảy ra nếu bạn đang làm việc trên nhiều mô hình (vì vậy các kho lưu trữ mutiple) – Alex

+0

@Alex - bạn có thể làm điều đó, có - nhưng sở thích của tôi là giữ chúng riêng biệt, và có Repositories nên lấy một đơn vị công việc trong ctor của chúng, được tạo trước (bởi một vùng chứa DI, khi có yêu cầu HTTP). Biết ý tôi là gì? – RPM1984

+0

Ồ, làm cách nào bạn có thể thực hiện công việc liên quan đến việc tạo bản ghi trong nhiều mô hình? tức là, tạo người dùng mới và bài đăng mới trong cùng một giao dịch. Và một câu hỏi nữa, tuổi thọ của bối cảnh HTTP làm gì? Cảm ơn! – Alex

6

Sử dụng 1 DbContext! Điều đó sẽ làm cho cuộc sống dễ dàng hơn cho bạn. Đừng lo lắng về hiệu suất, dữ liệu không cần thiết hoặc được truy vấn sẽ không được tải và sẽ không tiêu tốn bất kỳ tài nguyên nào.

public class UserContext : DbContext 
{ 
    public DbSet<User> Users { get; set; } 
    public DbSet<Post> Posts { get; set; } 
    public DbSet<Comment> Comments { get; set; } 
} 

Đối với một số trường hợp, bạn có thể muốn 2 ngữ cảnh trở lên.

Ngữ cảnh giống như trên để giữ tất cả dữ liệu mặt trước cần thiết cho ứng dụng của bạn hoạt động và ngữ cảnh khác - ví dụ - để lưu trữ các báo cáo được tạo từ dữ liệu front-end đó và chỉ được sử dụng trong ứng dụng của bạn.

+1

Được bình chọn là câu trả lời duy nhất không gợi ý để bọc 'DbContext' với một số' IUnitOfWork' :) –

0

Tôi đang thử nghiệm với UnitofWork, đây là những gì tôi đã đưa ra ...

Trước tiên tôi tạo ra một IUnitofWork mà chỉ chứa một phương pháp. Commit();

Sau đó dbContext của tôi trông như thế này

public class myContext : DbContext, IUnitOfWork 
{ 
    public DbSet<Users> Users { get; set; } 
    public DbSet<Addresses> Address { get; set; } 

    public void Save() 
    { 
     SaveChanges(); 
    } 
} 

lớp kho của tôi mất một UnitofWork trong ctors của họ.

public class UserRepository : IRepository<Position>  
{ 
    private myContext _context; 

    public UserRepository (IUnitOfWork unitOfWork) 
    { 
     if (unitOfWork == null) 
      throw new ArgumentNullException("unitOfWork"); 

     _context = unitOfWork as myContext; 
    } 
    /// other methods /// 
} 

Sau đó các mã trong bộ điều khiển sẽ là một cái gì đó như thế này

_unitOfWork = new myContext(); 
_userDB = new UserRepository(_unitOfWork); 
_addressDB = new AddressRepository(_unitOfWork); 
_userDB.Add(newUser); 
_addresesDB.Add(newAddress); 
_unitOfWork.Save(); 

tôi đã sửa lỗi và chứng minh rằng không có dữ liệu được cam kết cho đến khi phương thức Save của _unitOfWork được gọi. Những thứ rất tuyệt vời !!

Các vấn đề liên quan