Most of this would be accomplished by injecting a repository who's implementation gives out those non-tracked objects or talks read/writes to flat files.
A lot of what the conceptual repository does is at cross purposes with UoW. The repo implementation ends up having a lot of these:
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();
}
}
}
As you can see, there isn't a whole lot of usage of the UoW. I think most of the usefulness of EF when using a repository is in not having to write SQL by hand.
However, UoW works well when there is no repository abstraction and the business logic works directly with the entities and the context. For instance in an UI <-> MVC <-> Service Layer scenario you might have the MVC controller instruct the service layer to create a new invoice:
IMyService svc = new MyServiceLayer();
IInvoice invoice = svc.CreateInvoiceForCustomer(customer, items, paymentInfo);
InvoiceViewModel invoiceVm = Map(invoice);
return RedirectToAction("Display", "Invoice", invoiceVm);
You can picture that the service layer might do the following:
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
};
}
}
In this example, the UoW pattern acts as a replacement for a transaction. You get Atomicity without getting your hands dirty.
The real power of UoW is in a stateful system, like WPF, where you could have a long-lived context that is used to process an big Queue of commands that are executing asynchronously on a different thread.