Как охватить Dbcontexts (чтобы предотвратить одноэлементный контекст для всего приложения) - PullRequest
11 голосов
/ 28 января 2011

Мне было интересно, как вы расширяете ваши Dbcontexts в Entity Framework, чтобы вы не использовали один Dbcontext для всего вашего приложения. Я новичок в Entity Framework и читаю учебные пособия, но все они использовали один Dbcontext в качестве примера, поэтому EF для меня сейчас почти черный ящик.

Скажем, например, у меня есть 3 модели:

  • Пост
  • Пользователь
  • Комментарий

Каждая модель связана друг с другом (сообщение принадлежит пользователю, комментарий принадлежит пользователю и сообщению). Я делаю Dbcontext для каждого в отдельности? Но это было бы неправильно, поскольку все они связаны, или я бы сделал Dbcontext для каждого сценария, который мне нужен? Например, если мне нужно только запросить сообщение и комментарии, а не пользователя, это будет PostCommentsContext. И тогда у нас будет PostUserCommentContext ...

Ответы [ 3 ]

7 голосов
/ 28 января 2011

Лучшим решением было бы использовать Единицу работы , чтобы обернуть контекст данных, а также управлять временем жизни соединения и позволить вам работать с несколькими репозитариями (если вы были склонны к отказу этот путь).

Краткое описание реализации:

  • Создайте интерфейс (IUnitOfWork), который предоставляет свойства для ваших DbSet, а также один метод с именем Commit
  • Создать реализацию (EntityFrameworkUnitOfWork), реализуя по мере необходимости. Коммит просто вызывает SaveChanges для базового класса (DbContext), а также обеспечивает хорошую привязку для логики в последнюю минуту.
  • Ваш контроллер принимает IUnitOfWork, используйте DI (предпочтительно) для разрешения EntityFrameworkUnitOfWork, с временем жизни в контексте HTTP-контекста ( StructureMap хорошо для этого)
  • (необязательно, но рекомендуется) создайте репозиторий , который также принимает IUnitOfWork, и отработайте его через контроллер.

НТН

РЕДАКТИРОВАТЬ - В ответ на комментарии

О, как вы можете выполнять работу, которая включает создание записей в нескольких моделях? то есть создать нового пользователя и новое сообщение в одной транзакции.

Учитывая ваше использование ASP.NET MVC, ваши контроллеры должны принимать IUnitOfWork в своем конструкторе.

Вот пример, основанный на том, что вы спросили

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

И еще один вопрос: что делает время жизни в контексте HTTP?

Объекты в DI-talk имеют параметры управления областью действия, которые включают в себя поток, сеанс, http-запрос, одиночный вызов и т. Д.

HTTP-контекстная область является рекомендуемой настройкой для веб-приложений. Это означает «создать контекст, когда поступит HTTP-запрос, и избавиться от него, когда запрос завершится».

6 голосов
/ 28 января 2011

Используйте 1 DbContext!Это облегчит вам жизнь.Не беспокойтесь о производительности, данные, которые не нужны или запрошены, не будут загружены и не потребляют никаких ресурсов.

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

Для некоторых сценариев может потребоваться 2 или более контекстов.

Контекст, подобный приведенному выше, для хранения всех интерфейсных данных, необходимых для работы вашего приложения, и другой контекст - в качестве примера - для хранения отчетов, сгенерированных из этих интерфейсных данных, и который используется только всерверная часть вашего приложения.

0 голосов
/ 31 марта 2011

Я экспериментирую с UnitofWork, вот что я придумала ...

Сначала я создал IUnitofWork, который содержит только один метод.Commit();

Тогда мой dbContext выглядит следующим образом

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

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

Мои классы репозитория принимают UnitofWork в своих 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 ///
}

Тогда код в контроллере будетчто-то вроде этого

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

Я отладил и доказал, что никакие данные не передаются, пока не будет вызван метод Save _unitOfWork.Очень классная штука !!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...