没有人喜欢我的第一个问题: 使用Unity for Work of Work/Repository模式创建Entity Framework对象
所以我设法把它改写成你可以阅读而不会入睡/失去生存意愿的东西.
我正在创建一个对象DataAccessLayer,它在构造函数中有2个接口:IUnitOfWork和IRealtimeRepository:
public DataAccessLayer(IUnitOfWork unitOfWork,
IRealtimeRepository realTimeRepository)
{
this.unitOfWork = unitOfWork;
this.realTimeRepository = realTimeRepository;
}
Run Code Online (Sandbox Code Playgroud)
现在,实现IRealtimeRepository的构造函数也接受IUnitOfWork参数:
public DemoRepository(IUnitOfWork unitOfWork)
{
this.unitOfWork = unitOfWork;
}
Run Code Online (Sandbox Code Playgroud)
在Unity容器设置中,我然后添加两个实现:
container.RegisterType<IUnitOfWork, communergyEntities>();
container.RegisterType<IRealtimeRepository, DemoRepository>();
Run Code Online (Sandbox Code Playgroud)
会发生什么是Unity创建2个新的IUnitOfWork实例(实际上是一个实体框架数据上下文),一个用于DataAccessLayer构造函数,一个用于DemoRepository构造函数
由于这是针对工作单元模式,因此重用相同的实例非常重要.有任何想法吗?我之前已经问过类似的问题,但是没有被接受
我正在使用" 存根技术 "来更新我的POCO(用于分离的上下文,ASP.NET MVC).
这是我目前在我的控制器中的代码(可以工作):
[HttpPost]
public ActionResult Edit(Review review)
{
Review originalReview = _userContentService.FindById(review.PostId) as Review;
var ctx = _unitOfWork as MySqlServerObjectContext;
ctx.ApplyCurrentValues("MyEntities.Posts", review);
_unitOfWork.Commit();
// ..snip - MVC stuff..
}
Run Code Online (Sandbox Code Playgroud)
如你所见,到处都有代码味道.:)
几点:
void Commit();IUserContentService并IUnitOfWork通过DI注入IUserContentServiceFind在存储库中调用,使用ObjectContext.这些是我不喜欢上面代码的两件事:
MySqlServerObjectContext.ApplyCurrentValues我基本上希望我的代码看起来像这样:
[HttpPost]
public ActionResult Edit(Review review)
{
_userContentService.Update(review);
_unitOfWork.Commit();
// ..snip - MVC stuff..
}
Run Code Online (Sandbox Code Playgroud)
任何想法我怎么能这样做?(或类似的东西).
我已经很聪明地根据类型(泛型,复数的组合)来计算实体集名称,所以不要过于担心.
但我不知道放在哪里最好的地方 …
据我了解,UnitOfWork类旨在表示域中业务事务的概念.它并不直接表示数据库事务,这只是一个可能的实现的细节.
问:那么为什么关于工作单元模式的大量文档会引用"提交"和"回滚"方法?
这些概念对域或域专家毫无意义.业务事务可以"完成",因此UnitOfWork应该提供"完整"方法.同样,它不应该被建模为"清除"而不是"回滚"方法吗?
更新:
答:以下两个答案都是正确的.它们是UoW的两种变体:对象注册和呼叫者注册.在对象注册中,Rollback用于撤消对所有内存中对象的更改.在调用者注册中,Rollback用于清除所有记录的更改,以便后续调用Commit将不执行任何操作.
abstraction domain-driven-design unit-of-work separation-of-concerns
我编写了一个不暴露公共Commit()方法的UnitOfWork实现.相反,UnitOfWork实现IDisposable并且在Dispose()方法中执行Commit .我没有看到任何直接的问题,但它似乎是非正统的,所以我想知道你们是否可以指出一些不这样做的主要原因,我忽略了.
以下是一些示例代码:
public class DataService
{
public DataService()
{
_db = new MyDataContext();
_exceptionHandler = new SqlExceptionHandler();
}
private readonly MyDataContext _db;
private readonly SqlExceptionHandler _exceptionHandler;
public void Add(Product product, Cart cart)
{
using(UnitOfWork unitOfWork = new UnitOfWork(_db, ex=>_exceptionHandler.Handle(ex)))
{
unitOfWork.Create<CartItem>(new CartItem{CartId = cart.Id, ProductId = product.Id});
unitOfWork.Update<Product>(x => x.Id == product.Id, product => { product.OrderCount++; });
}
}
}
public class UnitOfWork : IDisposable
{
private readonly DataContext _dataContext;
private readonly Func<Exception, …Run Code Online (Sandbox Code Playgroud) 我试图在单个视图中更新复杂模型.我正在使用ASP.NET MVC3,Entity Framework with Code first,工作单元,通用存储库模式..但是当我尝试更新模型时,我想出了这个错误:
发生了引用完整性约束违规:定义引用约束的属性值在关系中的主体和从属对象之间不一致.
这是我的简化视图模型:
public class TransactionViewModel
{
public Transaction Transaction { get; set; }
public bool IsUserSubmitting { get; set; }
public IEnumerable<SelectListItem> ContractTypes { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
这是我的简化复杂模型,并作为其导航属性之一的示例.Transaction与其所有导航属性具有一对一的关系:
public class Transaction
{
[Key]
public int Id { get; set; }
public int CurrentStageId { get; set; }
public int? BidId { get; set; }
public int? EvaluationId { get; set; }
public virtual Stage CurrentStage { get; set; }
public virtual Bid Bid …Run Code Online (Sandbox Code Playgroud) 如何使用Autofac在WCF服务中实现工作单元模式?
使用Autofac的wcf集成,可以轻松地将每个调用(或Autofac术语LifetimeScope)工作接口单元中的相同实例注入到我的服务和存储库中 - 我所遵循的是在返回WCF服务时提交工作单元更改的方法如果没有任何例外,显然只会打电话.
我已经看到使用自定义端点行为与WCF和Autofac,这基本上是我开始,但不处理异常.
目前我所拥有的是IOperationInvoker在Invoke中启动工作单元并仅在没有任何异常的情况下提交它.这种方法的问题是我需要在方法中解析我的工作单元实例,Invoke这给了我一个不同于注入我的服务和存储库的实例AutofacInstanceProvider.
我遇到了一个问题,EF寻找这个问题的最佳实践:
public void TestEntityFramework_UOWImplementation()
{
using (UnitOfWorkInventory uow = new UnitOfWorkInventory())
{
IMaterialRepository repos = new MaterialRepository(uow);
Material mat = GetMaterial("Mikes Material", 1);
mat.CostPrice = 20;
repos.InsertOrUpdate(mat);
uow.Commit();
}
}
private Material GetMaterial(string sku, int clientId)
{
IMaterialRepository repos = new MaterialRepository(new UnitOfWorkInventory();
return repos.Find(sku, clientId);
}
Run Code Online (Sandbox Code Playgroud)
在TestEntityFramework_UOWImplementation()方法中,它很好,我调用为我的工作单元创建一个范围..并在其中创建一个存储库.
但是,当我想getMaterials()如下所示..我无法访问工作单元或存储库,除非我实际将其作为参数传递!这显然不是特别好.
人们如何解决这个问题?
提前致谢!
尼尔
我已经在网上搜索了使用Entity Framework实现存储库/工作单元模式的良好实现.我遇到的一切要么在抽象中的某个点紧密耦合,要么假设DbContext工作单元和存储库使用的是共享的,并且应该为整个HTTP请求(每个请求的实例通过依赖注入)生效.
例如,假设您正在从服务层使用存储库,则服务构造函数可能如下所示:
public DirectoryService(IUnitOfWork unitOfWork, ICountryRepository countryRepo, IProvinceRepository provinceRepo)
{
/* set member variables... */
}
Run Code Online (Sandbox Code Playgroud)
工作单元的构造函数可能如下所示:
public UnitOfWork(IDbContext context)
{
_context = context;
}
Run Code Online (Sandbox Code Playgroud)
并且存储库构造函数可能如下所示:
CountryRepository(IDbContext context)
{
_context = context;
}
Run Code Online (Sandbox Code Playgroud)
此解决方案盲目地假设依赖注入正在设置工作单元和存储库以使用每个请求的实例共享相同的IDbContext.这真的是一个安全的假设吗?
如果您对每个请求的实例使用依赖注入,则会将相同的IDbContext注入到多个工作单元中.工作单位不再是原子的,是吗?我可能在一个服务中有待更改,然后在另一个服务中提交,因为上下文在多个工作单元之间共享.
对我而言,为IDbContextFactory每个工作单元设置一个新的数据库上下文似乎更有意义.
public interface IDbContextFactory
{
IDbContext OpenContext();
}
public class UnitOfWork
{
private IDbContextFactory _factory;
private IDbContext _context;
UnitOfWork(IDbContextFactory factory)
{
_factory = factory;
}
internal IDbContext Context
{
get { return _context ?? (_context = _factory.OpenContext()); } …Run Code Online (Sandbox Code Playgroud) 我正在尝试用NHibernate实现UnitOfWork和Repository模式.我正在寻找在工作单元实例和存储库实例之间共享会话的最佳方法.
最明显的方法是ThreadStatic在UnitOfWork课堂上介绍属性
public class UnitOfWork : IUnitOfWork
{
public static UnitOfWork Current
{
get { return _current; }
set { _current = value; }
}
[ThreadStatic]
private static UnitOfWork _current;
public ISession Session { get; private set; }
//other code
}
Run Code Online (Sandbox Code Playgroud)
然后在Repository课堂上:
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
protected ISession Session { get { return UnitOfWork.Current.Session; } }
//other code
}
Run Code Online (Sandbox Code Playgroud)
但是我不喜欢上面列出的实现,并决定找到另一种方法来做同样的事情.
所以我带来了第二种方式:
public interface ICurrentSessionProvider : …Run Code Online (Sandbox Code Playgroud) 我正在使用带有UoW模式的EF 6.我在我的UoW中定义了多个上下文,因为我使用的是来自多个数据库的数据.除了我定义的CommitAsync函数之外,一切似乎都正常工作.这是我的代码:
public async Task CommitAsync()
{
try
{
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
if (_context1 != null)
await _context1.SaveChangesAsync();
if (_context2 != null)
await _context2.SaveChangesAsync();
scope.Complete();
}
}
catch (DbEntityValidationException ex)
{
//..
}
}
Run Code Online (Sandbox Code Playgroud)
当我运行此代码保存两个上下文中的更改时,我得到:
事务管理器已禁用其对远程/网络事务的支持.(HRESULT异常:0x8004D024)
等待_context2.SaveChangesAsync(); 是错误发生的地方.如果我从此函数中删除TransactionScope,代码似乎没有错误.我对于删除多个上下文的范围犹豫不决.
以防万一它会有所帮助,这是我用来调用这个函数的代码:
state.Name = "Texas";
_uow.StateRepository.Update(state);
user.FirstName = "John";
_uow.UserRepository.Update(user);
await _uow.CommitAsync();
Run Code Online (Sandbox Code Playgroud)
谢谢!
unit-of-work ×10
c# ×4
.net ×2
asp.net-mvc ×2
autofac ×2
abstraction ×1
async-await ×1
datacontext ×1
linq-to-sql ×1
nhibernate ×1
repository ×1
wcf ×1