Вопрос

In the domain core of my application, I have an Order object. It has private setters, since those properties should not be modified willy-nilly, but only within the context of performing one of the public functions on the object.

public class Order
{
    public int Id { get; private set; }
    public int MarketplaceId { get; private set; }
    public int CustomerId { get; set; }
    public OrderStatus Status { get; private set; }

    public bool Validate() { //stuff }
    public void Fulfill()
    {
        //messes with order status, etc.
    }

}

I have an OrderRepository for data access, which lives on the outer edges of my architecture, which has a GetOrderById(int orderId) function. This function pulls from the database to populate an Order object. I need to be able to populate my Order object, but I'd rather not expose the properties as public, since any other application or service utilizing the Order object should not be setting those properties. How can I architect this to populate the Order object from the repository but still retain my encapsulation on the Order object?

It seems like doing this through one or more constructors (overloads) would be messy, but I'm not sure what else to do.

Это было полезно?

Решение

That Order is an object but I'm quite certain is NOT a Domain object. Validate() and Fulfill() have no place there, but that's another story.

It doesn't matter if you're using an ORM, it does matter how the object state is stored. In your case the most straighforward way is to either use AutoMapper to map from EF entities to the Order or (and I favor this approach) to have a OrderStateSave DTO which will be passed as a constructor argument.

Personally I prefer to serialize directly the object so restore is a trivial deserialize. To keep it simple, this means I have a column Serialized next to the PK column. It's a additional step when saving but it's easy one.

Другие советы

How can I architect this to populate the Order object from the repository but still retain my encapsulation on the Order object?

You need to use an Object-relational mapper. Good ORM will allow you to populate private fields so you can have a proper encapsulation in your domain objects.

It seems like doing this through one or more constructors (overloads) would be messy, but I'm not sure what else to do.

The only requirement NHibernate puts on your domain objects is for it to have an empty private constructor. Also be aware of popular 'Fluent/Code' mappings which make it hard to keep fields private. Instead, you can just use classic HBM mapping files, and catch all potential mapping errors by writing integration tests.

By using reflection:

var order = new Order();
order
   .GetType()
   .GetProperty("MarketplaceId", BindingFlags.Instance|BindingFlags.NonPublic)
   .SetValue(order, 20);

There are also several examples which uses delegates for the assignment (to make it faster). Here is an example which I made a couple of years ago: https://webserver.codeplex.com/SourceControl/latest#693649

You should have a look at this interesting article, it summarizes what you're trying to do: Strengthening your domain by disabling setters.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top