You can add idea 1 on top of idea 2. So I would start with idea 2.
I would avoid having lengthy conversation stored locally at the client end. It will result in synchronization complexity and the client may end up being very chatty (and thus slow).
Try looking at your web service as a facade. Try sticking to a single call - complete operation pattern.
Ask yourself why do I need a client side unit of work.
How large is your application? There's a good chance you're overthinking this. Unless the application is a large, enterprise-grade application, the high degree of loose coupling you are advocating is probably unnecessary.
If you decide that this level of loose coupling is still necessary, create a service layer that returns "service" objects. This fulfills a similar function to View Models in MVC. You will then write code in your service layer that maps objects from your domain model to your service model.
Note that part of your struggle may be due to the fact that, while your Data Repository is returning CRUD objects, your Service Layer should be returning the result of actions. For example:
public InvoiceView GetInvoice(int invoiceID);
returns a InvoiceView
object containing whatever data you wish to expose to the public, including Name, Address, Line Items and so forth, from several different tables/objects in your domain.
public class InvoiceView
{
public int InvoiceID;
public Address ShippingAddress;
public Address BillingAddress;
public List<LineItem> LineItems;
...
}
Similarly, there will be Service Layer methods that simply performs an action and returns an object indicating the result of the action:
public TransactionResult Transfer(
int sourceAccountID, int targetAccountID, Money amount, ValidationToken token);
IMPORTANT: You'll never be able to completely decouple from your data. Your consumer will always have to have some knowledge of the data, even if it's just an object ID or UUID.
Best Answer
The purpose of a Repository is to provide an abstraction layer for data access. That abstraction layer should shield the user of the repository from the details of accessing the data. Things like connection strings, data sources, switching to a different data source... Your user shouldn't have to worry about those things.
In other words, the user of a Repository should not have to be concerned about where the data is coming from. That is an implementation detail. How you implement that detail is entirely up to you and your software's specific requirements.