EF6,工作单元和存储库模式 - 这是同步服务的错误模式吗?

时间:2015-03-12 21:44:40

标签: c# entity-framework-6 repository-pattern unit-of-work

我正在Salesforce环境和本地环境之间编写同步服务。由于每天的API请求数量限制,我对Salesforce API的使用纯粹是在批处理级别,尽管我确实有原子级故障的详细信息。但是,我想在本地环境中保存原子级别的更改,因为如果一个实体失败,我不希望整个事务失败。

我正在使用具有工作单元和存储库模式的Entity Framework 6。这是我的相关代码(下面的实施细节):

IUnitOfWork

public interface IUnitOfWork: IDisposable
{
    IReadUpdateRepository<EntityType1> EntityType1Repository { get; }
    ISyncRepository<EntityType2> EntityType2Repository { get; }
    ISyncRepository<EntityType3> EntityType3Repository { get; }
...other repos
    void SaveChanges();
}

IUnitOfWork的实现

public class UnitOfWork : IUnitOfWork
{
    private bool _isDisposed;
    private DbContext _context;
    private ISyncRepository<Entity> _entityRepo;

...other private repos
    public UnitOfWork(DbContext context)
    {
        _context = context;
    }


    public ISyncRepository<Entity> EntityRepository
    {
        get
        {
            if (_entityRepo == null)
                _entityRepo = new GenericSyncRepository<Entity>(_context);

            return _entityRepo ;
        }
    }

...other getters for other repos

    public void SaveChanges()
    {
        //client classes handle all errors here
        _context.SaveChanges();
    }

    private void dispose(bool isDisposing)
    {
        if (!_isDisposed)
        {
            if (isDisposing)
                _context.Dispose();
        }

        _isDisposed = true;
    }

    public void Dispose()
    {
        dispose(true);
    }
}

ISyncRepository

public interface ISyncRepository<T> where T : BaseEntity
{
    void DeleteItems(IEnumerable<T> items);
    void DeleteItemsById(IEnumerable<int> ids);
    void DeleteItem(T item);
    void InsertItems(IEnumerable<T> items);
    void Insert(T item);
    T GetItemById(int id);
    List<T> GetItems(Expression<Func<T, bool>> predicate = null,     Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, string includeProperties = "");

}

ISyncRepository的实现

public class GenericSyncRepository<T> : ISyncRepository<T> where T : BaseEntity
{
    private readonly DbContext _context;
    private readonly DbSet<T> _set;

    public GenericSyncRepository(DbContext context)
    {
        _context = context;
        _set = _context.Set<T>();
    }

    public T GetItemById(int id)
    {
        var result = _set.Find(id);

        return result;
    }

    public List<T> GetItems(Expression<Func<T, bool>> predicate = null, Func<IQueryable<T>,IOrderedQueryable<T>>  orderBy = null ,string includeProperties = "")
    {
        IQueryable<T> query = _set.AsExpandable();

        if (predicate != null)
        {
            query = query.Where(predicate);
        }


        if (!String.IsNullOrEmpty(includeProperties))
        {
            var splitProps = includeProperties.Split(',');
            foreach (var prop in splitProps)
            {
                query = query.Include(prop);
            }
        }

        if (orderBy != null)
        {
            return orderBy(query).ToList();
        }

        return query.ToList();
    }

    public void DeleteItemsById(IEnumerable<int> ids)
    {

        var items = ids.Select(i => _set.Find(i));

        DeleteItems(items);
    }

    public void DeleteItem(T item)
    {
        _set.Remove(item);
    }

    public void DeleteItems(IEnumerable<T> items)
    {
        _context.Set<T>().RemoveRange(items);
    }

    public void Insert(T item)
    {
        _set.Add(item);
    }

    public void InsertItems(IEnumerable<T> items)
    {
        _set.AddRange(items);
    }

    public List<T> GetViewItems(Expression<Func<T, bool>> predicate)
    {
        IQueryable<T> query = _set.AsExpandable();

        return query.Where(predicate).ToList();
    }
}

我在与同步中涉及的每个对象组相关的服务中使用此存储库,我通过构造函数注入IUnitOfWork:

 private readonly IUnitOfWork _uow;

public EntityDataService(IUnitOfWork uow, ICamsSfDTOMapper mapper)
    {
        _uow = uow;
    }

然后使用UoW获取存储库以执行查询:

var repo = _unitOfWork.PartyRepository;
var p = repo.GetItems(p => Ids.Contains(someValue));

当进行插入或更新时,我可以调用SaveChanges:

_unitOfWork.SaveChanges();

这非常适合数据检索,但是对于数据持久性,我遇到了麻烦。在本地域方面,我想逐个遍历对象,保存更改或插入并调用SaveChanges来保持。如果发生错误,我将其存储在我在每个同步步骤结束时记录的结果对象中,并继续执行下一个对象以进行处理。

但是,由于我的应用程序当前是结构化的,如果在SaveChanges上发生数据库异常,则该验证错误将保留在上下文中,直到它被释放为止。由于此上下文被注入到UoW类的每个存储库中,因此我认为它是整个同步过程的生命周期。

我在使用TopShelf托管的WindowsService中使用Autofac for DI,我正在注册我的UoW:

builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().WithParameter("context", new EntityModel());

以下是我的问题:

  1. 此问题是否应发布到Code Review:)
  2. 我觉得我应该用UoW反转我的存储库,UoW被传递到每个存储库,我的存储库被传递到每个服务(一个服务可以使用多个存储库)
  3. 为每个SaveChanges启动一个新的DbContext并将一个DbContext(传递给UoW的那个)作为我的读取上下文以及在SavingChanges时新增的所有其他上下文是否有意义?
  4. 任何帮助都将不胜感激。

1 个答案:

答案 0 :(得分:1)

  1. 不打扰我,我只使用SO而不打算去任何其他地方,并且不要介意在SO上有这样的问题。
  2. 我强烈建议您的服务IRepository和您的存储库请求IUoW。我甚至认为IRepository不仅仅是EF的障碍。我通常只使用存储库
    • 事先我知道我将实现非EF存储库,否则
    • 我想实现一些我希望从我的服务中抽象出来的实际逻辑,并且不会使它变得通用。例如。我会创建一个UserProfileRepository,它有SyncCurrentUserProfile之类的方法,而不是公开Add/Insert/Update。如果我不打算使用非基于EF的模型,则公开Add/Insert/Update不会增加等式。
  3. 这取决于。如果您不使用跟踪,并且随着时间的推移会发生很多无关的更改。是的,因为每次添加/更新某些内容时,它都会将其添加到上下文中,这会导致将来的添加/修改变得更慢。但是如果你在这里和那里添加/修改10件事情,除非你每次都需要一个新的背景,否则可能不会担心它。
  4. 我实际上正在写一篇关于此的博文。稍后会尝试发布链接。