Question

I'm a little overwhelmed with all of the information on DDD, unit of work, domain services, app services, etc. I'm trying to figure out how a persistence-ignorant domain model ultimately gets persisted, specifically in the context of unit-of-work and Entity Framework. Let's say I have an Order aggregate root, which I am attempting to keep in my persistence-ignorant domain model (the core of my architectural onion):

public class Order : EntityBase
{
    public int Id { get; private set; }
    public int MarketplaceId { get; private set; }
    public int CustomerId {get; set;}
    public List<OrderItem> Items { get; private set; }
    public List<OrderComment> Comments { get; private set; }

    public void AddItem(OrderItem item) { /**add item**/ }
    public void AddComment(OrderComment comment) { /**add comment**/ }
    public override bool Validate() { /**validate**/ }
    public void Cancel() { /**cancel**/ }
}

Let's say I have a process that updates a property on the Order entity, for example it changes the CustomerId associated with the order.

I have an IOrderRepository in my domain layer, which would have an implementation (in an outer layer) with a function like this:

Order GetOrder(int orderId)
{
    //get entity framework order, items, etc.
    //map to domain-layer order and return domain-layer order
}

void UpdateOrder(Order order)
{
    //get ENTITY FRAMEWORK order, order items, order comments, etc.
    //take DOMAIN order (passed in to this function), and update EF items fetched above
    //use a single EF unit of work to commit these changes
}

There's something wrong with my approach. The UpdateOrder function seems heavy for a small change; but it also seems I have to do that if my repository isn't aware of which items on the persistence-ignorant domain model have changed. Should I be handling every type of update in a separate repository function? UpdateMarketplace(int marketplaceId), UpdateCustomer(int customerId)?

As I'm typing this, I'm also wondering...maybe the way I have it above is not too heavy? If I change one property, even though I'm doing all of the above, perhaps Entity Framework will recognize that the values being assigned are the same and will only send the one db column update to SQL?

How can I take my Order domain model (fetching is straightforward enough), perform some operation or operations on it that may be limited in scope, and then persist the model using Entity Framework?

Was it helpful?

Solution

You need to look into the Unit of Work pattern. Your UoW keeps track of the changes, so when you get your order from your repository and modify it, you call UnitOfWork.SaveChanges() which should persist all the changes.

Using Entity Framework, your DbContext is basically the Unit of Work but I would create a simpler interface around it so you can abstract it away for easier usage in your higher layers.

Regarding EF, I would recommend mapping your domain entities directly using the code first approach. I would also turn off lazy loading and all the magic stuff so you have full control and less "surprises".

Unfortunately I'm not allowed to share our code but we have all this working pretty effectively with the new EF6 Alpha 3. I would recommend you taking a look at Microsoft Spain's nlayerapp for some implementation examples. I don't agree with many of their design decisions (also, see this review), but I think you can draw some inspiration from the Entity Framework parts. Take a look at their Unit of Work implementation and especially how they have abstracted it away for easier usage in the higher layers, and how they use it in their application services.

I will also recommend looking into creating a generic repository to avoid duplicating lots of logic in your aggregate specific repositories. MS Spain has one here, but you should also take a look at this thread.

OTHER TIPS

Please have a look at this SO question where I gave an example of how I've implemented UoW & Repositories.

As @Tommy Jakobsen told you, your domain entities should be your EF entities, it would avoid you to add a useless mapping layer.

Hope that helps!

You may check ASP.NET Boilerplate's Unit Of Work implementation: http://www.aspnetboilerplate.com/Pages/Documents/Unit-Of-Work

It's open source project, you can check codes. Also, you can directly use it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top