[英]EF6, Unit of Work and Repository Pattern - Is this the wrong pattern for a sync service?
I'm writing a sync service between our Salesforce environment and our local environment. 我正在编写Salesforce环境和本地环境之间的同步服务。 My use of the Salesforce API is purely on a batch level due to limitations on # of API requests per day, although I do have details on failures at the atomic level. 由于每天对API请求数量的限制,我对Salesforce API的使用纯粹是在批处理级别,尽管我确实在原子级别上有关于失败的详细信息。 However, I would like to save changes on a atomic level in my local environment as I don't want an entire transaction to fail if one entity fails. 但是,我想在本地环境中保存原子级别的更改,因为如果一个实体发生故障,我不希望整个事务失败。
I am using Entity Framework 6 with a Unit of Work and Repository pattern. 我正在使用带有工作单元和存储库模式的Entity Framework 6。 Here is my relevant code (Implementation Details Below): 这是我的相关代码(下面的实现详细信息):
IUnitOfWork IUnitOfWork
public interface IUnitOfWork: IDisposable
{
IReadUpdateRepository<EntityType1> EntityType1Repository { get; }
ISyncRepository<EntityType2> EntityType2Repository { get; }
ISyncRepository<EntityType3> EntityType3Repository { get; }
...other repos
void SaveChanges();
}
Implementation of IUnitOfWork 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 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 = "");
}
Implementation of ISyncRepository 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();
}
}
I am using this repository in services that relate to each object group involved in the sync, into which I inject the IUnitOfWork via the constructor: 我在与同步中涉及的每个对象组相关的服务中使用此存储库,我通过构造函数将IUnitOfWork注入其中:
private readonly IUnitOfWork _uow;
public EntityDataService(IUnitOfWork uow, ICamsSfDTOMapper mapper)
{
_uow = uow;
}
Then use the UoW to fetch repositories to performs queries: 然后使用UoW来获取存储库以执行查询:
var repo = _unitOfWork.PartyRepository;
var p = repo.GetItems(p => Ids.Contains(someValue));
And when inserts or updates are made, I can call SaveChanges: 当进行插入或更新时,我可以调用SaveChanges:
_unitOfWork.SaveChanges();
This works great for data retrieval, however for data persistence, I run into a snag. 这对于数据检索非常有用,但是对于数据持久性,我遇到了麻烦。 On the local domain side, I want to iterate through objects one by one, saving changes or inserting and calling SaveChanges to persist. 在本地域方面,我想一个接一个地遍历对象,保存更改或插入并调用SaveChanges以保持持久性。 If an error occurs, I store it in a result object that I log at the end of each sync step and continue onto the next object to do work on. 如果发生错误,则将其存储在结果对象中,并在每个同步步骤结束时记录该结果对象,然后继续处理下一个对象。
However, as my app is currently structured, if a database exception occurs on SaveChanges, that validation error remains in the context until it is disposed. 但是,由于我的应用程序当前已构建,因此如果SaveChanges上发生数据库异常,该验证错误将保留在上下文中,直到将其释放为止。 Since this context is injected into each repository in the UoW class, it sticks around for what I presume is the life of the entire sync process. 由于此上下文已注入到UoW类中的每个存储库中,因此我认为这是整个同步过程的生命周期。
I am using Autofac for DI in a WindowsService hosted using TopShelf and I'm registering my UoW as such: 我在使用TopShelf托管的WindowsService中将Autofac用于DI,并且正在这样注册我的UoW:
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().WithParameter("context", new EntityModel());
Here are my questions: 这是我的问题:
Any help would be appreciated. 任何帮助,将不胜感激。
IRepository
and your repository ask for IUoW
. 我强烈建议您针对IRepository
的服务以及您的存储库要求IUoW
。 I even like to think of IRepository
as more than just a barrier to EF. 我什至喜欢将IRepository
视为不仅仅是EF的障碍。 I normally only use a repository if either 我通常只使用一个存储库
SyncCurrentUserProfile
rather than exposing Add/Insert/Update
. 例如,我将创建一个UserProfileRepository,它具有SyncCurrentUserProfile
方法,而不是公开Add/Insert/Update
。 Exposing Add/Insert/Update
adds nothing to the equation if I don't plan to use a non EF based model. 如果我不打算使用基于非EF的模型,则公开Add/Insert/Update
不会对方程式添加任何内容。 I am actually writing a blog post about this. 我实际上是在撰写有关此内容的博客文章。 Will try to post a link later. 稍后将尝试发布链接。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.