1

Привет, я использую Unity для управления моими уровнями обслуживания, которые, в свою очередь, разговаривают с UnitOfWork, который управляет всеми репозиториями.UnitOfWork с Unity и Entity Framework

Некоторые из моих услуг называют другие услуги, мой вопрос в том, как я могу передать один и тот же UnitOfWork между уровнями обслуживания?

В моем случае все действия контроллера инициируются из графического интерфейса пользователя при каждом действии или событии каждой кнопки на таймере, поэтому у меня есть фабрика для создания UnitOfWork по требованию, но это вызывает проблемы, поскольку я не знаю, как пройти это UnitOfWork между службами.

Особенно сложно знать, как получить этот конкретный экземпляр экземпляра UnitOfWork, введенный в конструктор службы. Обратите внимание, что некоторые из служб могут быть длинными (10 минут или около того в фоновом потоке), я не знаю, влияет ли это на дизайн или нет.

В настоящее время служба, вызываемая из другой службы, создает собственный UnitOfWork, который вызывает проблемы как для транзакционного проектирования, так и для отслеживания сущности Entity.

Предложения приветствуются!

class OtherService : IOtherService 
{ 
    public OtherService(IUnitOfWorkFactory unitOfworkFactory, 
     ISettingsService settingsService) 
    { 
     UnitOfWorkFactory = unitOfworkFactory; 
     SettingsService = settingsService; 
    } 
    IUnitOfWorkFactory UnitOfWorkFactory; 
    ISettingsService SettingsService; 

    function SomeSeviceCall() 
    { 
     // Perhaps one way is to use a factory to instantiate a 
     // SettingService, and pass in the UnitOfWork here? 
     // Ideally it would be nice for Unity to handle all of 
     // the details regardless of a service being called from 
     // another service or called directly from a controller 
     // ISettingsService settingsService = 
     //  UnityContainer.Resolve<ISettingService>(); 

     using (var uow = UnitOfWorkFactory.CreateUnitOfWork()) 
     { 
      var companies = uow.CompaniesRepository.GetAll(); 
      foreach(Company company in companies) 
      { 
       settingsService.SaveSettings(company, "value"); 
       company.Processed = DateTime.UtcNow(); 
      } 
      uow.Save(); 
     } 
    } 
} 

class SettingsService : ISettingsService 
{ 
    public SettingsService(IUnitOfWorkFactory unitOfworkFactory) 
    { 
     UnitOfWorkFactory = unitOfworkFactory; 
    } 
    IUnitOfWorkFactory UnitOfWorkFactory; 

    // ISettingsService.SaveSettings code in another module... 
    function void ISettingsService.SaveSettings(Company company, 
     string value) 
    { 
     // this is causing an issue as it essentially creates a 
     // sub-transaction with the new UnitOfWork creating a new 
     // Entiy Framework context 
     using (var uow = UnitOfWorkFactory.CreateUnitOfWork()) 
     { 
      Setting setting = new Setting(); 
      setting.CompanyID = company.CompanyID; 
      setting.SettingValue = value; 
      uow.Insert(setting); 
      uow.Save(); 
     } 
    } 
} 
+1

Посмотрите на [этот вопрос] (http://stackoverflow.com/questions/10585478/one-dbcontext-per-web-request-why). Я думаю, что [выбранный ответ] (http://stackoverflow.com/a/10588594/264697) также касается вашего вопроса. – Steven

+0

@Steven спасибо, мне нравится идея дизайна команды/обработчика, как можно было бы получить контекст, разделенный на несколько сервисов, с помощью декоратора команд? Если у вас есть примеры кода вызывающего декоратора и возвращенных данных, которые будут иметь огромное значение. – g18c

+0

Я пропустил тот факт, что вы используете Unity. С Unity чрезвычайно сложно зарегистрировать общие декораторы (хотя вы можете заставить его работать с поддержкой перехвата Unity).Однако теоретически это просто вопрос определения декоратора (скажем, «TransactionCommandHandlerDecorator»), который получает введенную единицу работы и вызывает «uwo.Save» в методе «Handle», сразу после вызова 'украденного.Handle (command) '. Вы регистрируете этот декоратор, который будет обернут вокруг ваших обработчиков команд и зарегистрируйте единицу работы с образом жизни «на веб-запрос». – Steven

ответ

2

Привет Я боролся с этой проблемой, это то, что я придумал ...

public class UnitOfWorkFactory 
{ 
    private static readonly Hashtable _threads = new Hashtable(); 
    private const string HTTPCONTEXTKEY = 
     "AboutDbContext.UnitOfWorkFactory"; 

    public static IUnitOfWork Create() 
    { 
     IUnitOfWork unitOfWork = GetUnitOfWork(); 

     if (unitOfWork == null || unitOfWork.IsDisposed) 
     { 
      unitOfWork = new UnitOfWork(); 
      SaveUnitOfWork(unitOfWork); 
     } 
     return unitOfWork; 
    } 

    public static IUnitOfWork GetUnitOfWork() 
    { 
     if (HttpContext.Current != null) 
     { 
      if (HttpContext.Current.Items.Contains(HTTPCONTEXTKEY)) 
      { 
       return (IUnitOfWork)HttpContext 
        .Current.Items[HTTPCONTEXTKEY]; 
      } 
      return null; 
     } 

     var thread = Thread.CurrentThread; 

     if (string.IsNullOrEmpty(thread.Name)) 
     { 
      thread.Name = Guid.NewGuid().ToString(); 
      return null; 
     } 

     lock (_threads.SyncRoot) 
     { 
      return (IUnitOfWork)_threads[Thread.CurrentThread.Name]; 
     } 
    } 

    private static void SaveUnitOfWork(IUnitOfWork unitOfWork) 
    { 
     if (HttpContext.Current != null) 
     { 
      HttpContext.Current.Items[HTTPCONTEXTKEY] = unitOfWork; 
     } 
     else 
     { 
      lock (_threads.SyncRoot) 
      { 
       _threads[Thread.CurrentThread.Name] = unitOfWork; 
      } 
     } 
    } 

    public static void DisposeUnitOfWork(IUnitOfWork unitOfWork) 
    { 
     if (HttpContext.Current != null) 
     { 
      HttpContext.Current.Items.Remove(HTTPCONTEXTKEY); 
     } 
     else 
     { 
      lock (_threads.SyncRoot) 
      { 
       _threads.Remove(Thread.CurrentThread.Name); 
      } 
     } 
    } 
} 

public interface IUnitOfWork : IDisposable 
{ 
    void Commit(); 
    bool IsDisposed { get; } 
} 

public class UnitOfWork : MyContext 
{ 

} 

public abstract class Repository<T> 
    : IRepository<T>, IDisposable where T : class 
{ 
    private UnitOfWork _context; 

    private UnitOfWork Context 
    { 
     get 
     { 
      if (_context == null || _context.IsDisposed) 
       return _context = GetCurrentUnitOfWork<UnitOfWork>(); 

      return _context; 
     } 
    } 

    public TUnitOfWork GetCurrentUnitOfWork<TUnitOfWork>() 
     where TUnitOfWork : IUnitOfWork 
    { 
     return (TUnitOfWork)UnitOfWorkFactory.GetUnitOfWork(); 
    } 

    public IEnumerable<T> Get(Expression<Func<T, bool>> predicate) 
    { 
     return Context.Set<T>().Where(predicate).ToList(); 
    } 

    public bool Exists(Expression<Func<T, bool>> predicate) 
    { 
     return Context.Set<T>().Any(predicate); 
    } 

    public T First(Expression<Func<T, bool>> predicate) 
    { 
     return Context.Set<T>().Where(predicate).FirstOrDefault(); 
    } 

    public IEnumerable<T> GetAll() 
    { 
     return Context.Set<T>().ToList(); 
    } 

    public IEnumerable<T> GetAllOrderBy(Func<T, object> keySelector) 
    { 
     return Context.Set<T>().OrderBy(keySelector).ToList(); 
    } 

    public IEnumerable<T> GetAllOrderByDescending(Func<T, object> keySelector) 
    { 
     return Context.Set<T>().OrderByDescending(keySelector).ToList(); 
    } 

    public void Commit() 
    { 
     Context.SaveChanges(); 
    } 

    public void Add(T entity) 
    { 
     Context.Set<T>().Add(entity); 
    } 

    public void Update(T entity) 
    { 
     Context.Entry(entity).State = EntityState.Modified; 
    } 

    public void Delete(T entity) 
    { 
     Context.Set<T>().Remove(entity); 
    } 

    public void Dispose() 
    { 
     if (Context != null) 
     { 
      Context.Dispose(); 
     } 
     GC.SuppressFinalize(this); 
    } 
} 

public class MyContext : DbContext, IUnitOfWork 
{ 
    public DbSet<Car> Cars { get; set; } 

    public void Commit() 
    { 
     SaveChanges(); 
    } 

    protected override void Dispose(bool disposing) 
    { 
     IsDisposed = true; 
     UnitOfWorkFactory.DisposeUnitOfWork(this); 
     base.Dispose(disposing); 
    } 

    public bool IsDisposed { get; private set; } 
} 

Тогда я могу сделать:

using (var unitOfWork = UnitOfWorkFactory.Create()) 
{ 
    _carRepository.Add(new Car 
    { 
     Make = "Porshe", Name = "Boxter" 
    }); 

    _carRepository.Commit(); 
} 
1

Вы можете использовать какой-то «текущий» блок работы, привязанный к текущему потоку и явно разрешенный в служебном коде. Для этого вам нужен класс для хранения статического экземпляра потока UoW. Однако это не очень хорошее решение.

-1

Вам судить .. Я думаю, что вы делаете это вдвойне.

Пункт 1: http://www.britannica.com/topic/Occams-razor

Пункт 2: Из описания браузера объекта F2 Е.Ф. основного объекта, в DbContext ...


общественного класса DbContext Член System.Data. Объект

Реферат: Экземпляр DbContext представляет собой комбинацию Единица работыиРепозиторий шаблонов, которые могут быть использованы для запроса из базы данных и группировки изменений, которые затем будут записаны обратно в хранилище в виде единицы.

Смежные вопросы