2011-01-27 11 views
11

Zastanawiam się, w jaki sposób można rozszerzyć kontekst Dbcontexts w Entity Framework, aby nie używać pojedynczego kontekstu Dbcontext dla całej aplikacji. Jestem nowy w Entity Framework i czytałem tutoriale, ale wszystkie one używają pojedynczego Dbcontext jako przykładu, więc EF jest dla mnie prawie blackboxem właśnie teraz.Jak wykraczyć Dbcontexts (aby zapobiec pojedynczemu kontekstowi dla całej aplikacji)

Powiedzmy na przykład mam 3 modele:

  • post
  • użytkownika
  • Komentarz

Każdy model jest powiązane ze sobą (post należy do Użytkownika, komentarz należy do użytkownika i post). Czy mogę utworzyć kontekst Dbcontext dla każdego z osobna? Ale to nie byłoby poprawne, ponieważ wszystkie są ze sobą powiązane, czy też mogę utworzyć kontekst Dbcontext dla każdego scenariusza, którego potrzebuję? Na przykład, jeśli potrzebuję tylko zapytania o Post i komentarze, a nie użytkownika, będzie to PostCommentsContext. A następnie będziemy mieli PostUserCommentContext ...

+1

Również, gdy używasz UnitOfWork z ORM musisz wziąć pod uwagę, że jeśli commit nie powiedzie się, potrzebujesz nowego Kontekstu/Jednostki Pracy http://lavinski.tumblr.com/post/9114111237/object-relational-mapper -exceptions –

Odpowiedz

7

Najlepszym rozwiązaniem byłoby użycie jednostki Unit of Work do zawinięcia Kontekstu danych, a także do zarządzania czasem życia połączenia i umożliwienia pracy z wieloma repozytoriami (jeśli byłeś skłonny pójść tą ścieżką) .

Podsumowanie realizacji:

  • Załóż interfejs (IUnitOfWork), który eksponuje właściwości urządzenia DbSet „s, a także pojedynczy metoda zwana Commit
  • Załóż realizacji (EntityFrameworkUnitOfWork), wdrażanie jako wymagane. Zatwierdź po prostu wywołaj SaveChanges na klasie bazowej (DbContext), a także zapewnia dobre wejście dla logiki last minute.
  • Kontroler akceptuje IUnitOfWork użyj di (najlepiej) w celu rozwiązania EntityFrameworkUnitOfWork, z HTTP kontekście scoped dożywotnią ustawienie (StructureMap jest dobre dla tego)
  • (opcjonalne, ale zalecane) stworzyć repozytorium który również pobiera IUnitOfWork i działa, korzystając z kontrolera.

HTH

EDIT - W odpowiedzi na uwagi

Och, jak można to zrobić pracę, która polega na tworzeniu zapisów w wielu modelach wtedy? tj. utwórz nowego użytkownika i nowy post w tej samej transakcji.

Biorąc pod uwagę używanie ASP.NET MVC, kontrolery powinny zaakceptować IUnitOfWork w swoim konstruktorze.

Oto przykład, w oparciu o co pytasz

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

I jeszcze jedno pytanie, co robi HTTP kontekst życia lunetą zrobić?

Obiekty DI-talk mieć ustawienia zarządzania, które obejmują zakres od wątku, na sesję, na żądanie HTTP, Singleton, itp

HTTP kontekst jest zawężona zalecana dla aplikacji internetowych. Oznacza to "dodanie kontekstu, gdy przychodzi żądanie HTTP i pozbycie się go po zakończeniu żądania".

+0

obecnie używam wzorzec repozytorium. Jednak w przypadku modelu Jednostki Pracy, czy repozytoria nie powinny znajdować się w UU? Co jeśli robisz pracę na wielu modeli (stąd mutiple repozytoria) – Alex

+0

@Alex - można to zrobić, tak - ale mój preferencji jest, aby zachować ich indywidualne, i mieć repozytoria powinny jednostkę pracy w ich ctor, która była utworzone wcześniej (przez kontener DI, kiedy przychodzi żądanie HTTP). Wiesz co mam na myśli? – RPM1984

+0

Och, jak możesz wykonywać pracę polegającą na tworzeniu rekordów w wielu modelach? tj. utwórz nowego użytkownika i nowy post w tej samej transakcji. I jeszcze jedno pytanie, co robi okres życia z kontekstem HTTP? Dzięki! – Alex

6

Użyj 1 DbContext! To ułatwi ci życie. Nie martw się o wydajność, dane, które nie są potrzebne lub zapytania nie zostaną załadowane i nie zużyją żadnych zasobów.

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

Dla niektórych scenariuszy możesz potrzebować 2 lub więcej kontekstów.

Kontekst taki jak powyżej, przechowujący wszystkie dane frontonu potrzebne do działania aplikacji oraz inny kontekst do - na przykład - do przechowywania raportów wygenerowanych z tych danych frontonu i który jest używany tylko w back-end z twojej aplikacji.

+1

Upvoted za to, że jedyną odpowiedzią nie sugeruje, aby owinąć 'DbContext' z jakiegoś' IUnitOfWork' :) –

0

Ja eksperymentuje z UnitofWork, tutaj jest to, co mam wymyślić ...

pierwszy stworzył IUnitofWork który zawiera tylko jedną metodę. Commit();

Wtedy mój dbContext wygląda następująco

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

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

moich klas repozytorium wziąć UnitofWork w ich ctors.

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

Następnie kod w kontroler byłoby coś takiego

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

I debugowania i udowodnił, że żadne dane nie są zaangażowani aż metoda Zapisz się _unitOfWork nazywa. Bardzo fajne rzeczy !!

Powiązane problemy