C# 如何防止工作单元抽象泄漏
我正在学习良好的设计实践,并接触了工作单元设计模式以及存储库。这使我能够阻止应用程序逻辑了解持久性细节,但是我在处理一些特殊情况时遇到了一些困难 首先,在IUnitOfWork接口后面,我使用了一个使用EF访问数据的实现。对于我的查询,我使用规范设计模式来创建客户机可以使用的查询对象 因此,到目前为止,这件事基本上都是从数据源中抽象出来的,但这里有个交易: 假设我想用AsNoTracking选项检索一些数据。我应该如何告诉我的IUnitOfWork实现我不需要跟踪结果对象 此外,EF实际上不支持批处理CUD,也不支持将来的查询,但有一个扩展支持。如何以客户机代码完全不依赖于我持久化对象的方式来支持这一点?我可能想使用平面文件,因为所有的代码都很重要 TL;博士C# 如何防止工作单元抽象泄漏,c#,entity-framework,data-access-layer,C#,Entity Framework,Data Access Layer,我正在学习良好的设计实践,并接触了工作单元设计模式以及存储库。这使我能够阻止应用程序逻辑了解持久性细节,但是我在处理一些特殊情况时遇到了一些困难 首先,在IUnitOfWork接口后面,我使用了一个使用EF访问数据的实现。对于我的查询,我使用规范设计模式来创建客户机可以使用的查询对象 因此,到目前为止,这件事基本上都是从数据源中抽象出来的,但这里有个交易: 假设我想用AsNoTracking选项检索一些数据。我应该如何告诉我的IUnitOfWork实现我不需要跟踪结果对象 此外,EF实际上不支持
如何防止我的UnitOfWork抽象泄漏到我的客户机中?有人处理过这个问题吗?大多数问题都是通过注入一个存储库来完成的,该存储库的实现提供了那些未跟踪的对象,或者对平面文件进行读/写操作 概念存储库所做的很多事情与UoW有交叉的目的。回购协议的实施最终会产生很多这样的结果:
public class MyRepository : IWhateverRepository
{
// ...
public Customer GetCustomerByName(string customerName)
{
using (var db = new MyContext())
{
var customer = db.Customers.Where(cust => cust.Name == customerName).SingleOrDefault();
return customer;
}
}
public Customer StoreCustomer(Customer customer)
{
using (var db = new MyContext())
{
db.Entry(customer).State = customer.ID == 0 ? EntityState.Added : EntityState.Modified;
db.SaveChanges();
}
}
}
正如您所看到的,UoW的用法并不多。我认为EF在使用存储库时的最大用处在于不必手工编写SQL
但是,如果没有存储库抽象,并且业务逻辑直接与实体和上下文一起工作,那么UoW工作得很好。例如,在UI MVC服务层场景中,您可以让MVC控制器指示服务层创建新发票:
IMyService svc = new MyServiceLayer();
IInvoice invoice = svc.CreateInvoiceForCustomer(customer, items, paymentInfo);
InvoiceViewModel invoiceVm = Map(invoice);
return RedirectToAction("Display", "Invoice", invoiceVm);
您可以想象服务层可能会执行以下操作:
public ServiceResponse<Invoice> CreateInvoiceForCustomer(Customer customer, IEnumerable<InvoiceItem> items, PaymentInfo paymentInfo)
{
using (var db = new MyContext())
{
db.Entry(customer).State = customer.ID == 0 : EntityState.Added : EntityState.Modified;
var invoice = new Invoice
{
Customer = customer,
InvoiceDate = _timeService.Now(),
PaymentInfo = paymentInfo
};
foreach (var item in items)
invoice.Items.Add(items);
db.Invoices.Add(invoice);
db.SaveChanges();
return new SeviceResponse<Invoice>
{
IsSuccess = true,
Data = invoice
};
}
}
公共服务响应CreateInvoiceForCustomer(客户客户、IEnumerable项目、PaymentInfo PaymentInfo)
{
使用(var db=new MyContext())
{
db.Entry(customer.State=customer.ID==0:EntityState.Added:EntityState.Modified;
var发票=新发票
{
客户=客户,
InvoiceDate=\u timeService.Now(),
PaymentInfo=PaymentInfo
};
foreach(项目中的var项目)
发票.项目.添加(项目);
db.发票.添加(发票);
db.SaveChanges();
返回新的服务响应
{
IsSuccess=true,
数据=发票
};
}
}
在本例中,UoW模式充当事务的替换。你得到原子性而不弄脏你的手
UoW的真正功能是在有状态系统中,如WPF,您可以使用一个长期存在的上下文来处理在不同线程上异步执行的大量命令。在我的情况下,我使用Winforms,需要访问多个存储库并保持它们之间的数据同步,因此,我可以查询多个存储库并在演示者上同步保存。您的意思是,我可以在存储库中完成所有这些“NoTracking”部分,我认为这是正确的。虽然这并没有给我一个直接的方法来完成问题的“批处理”部分,但我想我可以从存储库返回一个带有值(甚至是元组)的DTO。我只是想知道世界其他地方是如何处理它的。如果你想让存储库参与到一个工作单元中,那么你必须在这个抽象级别上使用你自己的UoW实现。另一种方法是将存储库从等式中去掉(或者您正在进行域驱动设计?)。如果您不需要将实体存储在平面文件中,那么在设计中就没有多少理由考虑到它。事实上,这是编码的另一条“规则”——Y.A.G.N.I你不需要它(所以不要写它)。我有一个抽象的工作单元。目前唯一的实现是对EF隐藏DBContext对象。不管怎样,我想你是对的。我不需要它。我只需要保持持久层的细节不泄漏到其他层。无论如何,这是一个学习TDD、MVP、EF等适当分层概念的宠物项目。感谢您的帮助:)