1

嗨,我正在使用 Unity 来管理我的服务层,而后者又与管理所有存储库的 UnitOfWork 对话。

我的一些服务调用其他服务,我的问题是如何在服务层之间传递相同的 UnitOfWork?

在我的情况下,所有控制器操作都是从 GUI 对每个按钮操作或计时器上的事件启动的,这就是为什么我有一个工厂来按需创建 UnitOfWork,但这会导致问题,因为我不知道如何在服务之间传递这个 UnitOfWork .

尤其困难的是知道如何将这个特定的 UnitOfWork 实例注入到服务构造函数中。请注意,某些服务可能运行时间很长(后台线程上运行 10 分钟左右),我不知道这是否对设计有任何影响。

目前,从其他服务调用的服务正在创建自己的 UnitOfWork,这会导致事务设计和实体框架实体跟踪出现问题。

非常欢迎提出建议!

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

3 回答 3

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();
}
于 2012-06-07T13:15:53.770 回答
1

您可以使用某种与当前线程相关联并在服务代码中明确解析的“当前”工作单元。您需要类来保存 UoW 的线程静态实例来实现这一点。但是,这不是很好的解决方案。

于 2012-06-07T07:28:07.473 回答
-1

你是法官......我认为你是双重的。

第 1 点: http ://www.britannica.com/topic/Occams-razor

第2点:从EF主对象的F2对象浏览器描述中,DBContext...


System.Data.Entity 的公共类 DbContext 成员

摘要:DbContext 实例代表了工作单元 存储库模式的组合,因此它可以用于从数据库中查询并将更改组合在一起,然后将这些更改作为一个单元写回存储。

于 2015-12-28T20:25:48.373 回答