I have a set of entities, for now represented by very simple classes (further simplified for this example):

public class Item
{
    public string Name { get; private set; }
    public double MainValue { get; private set; }  //should be exposed for editing in GUI
    public double Value { get; private set; }  //should be exposed for editing in GUI
}

public class Record
{
    public Item Item { get; private set; }
    public double Quantity { get; private set; } //should be exposed for editing in GUI
    public double MainValue { get { return Item.MainValue*Quantity; } }
    public double Value { get { return Item.Value*Quantity; } }
}

public class DayAccount
{
    public DateTime Date { get; private set; }
    public IEnumerable<Record> Records { get; private set; }
    public double MainValueGoal { get; private set; }   //should be exposed for editing in GUI
    public double MainValueTotal { get { return Records.Sum(r => r.MainValue); } }
    public double ValueTotal { get { return Records.Sum(r => r.Value); } }

    public void Add(Record record) {}
    public void Remove(Record record) {}
}

There is going to be a repository class for accessing, adding and persisting DayAccount entities, but that's pretty much it. The end user should be able to modify some properties of these entities through the GUI if he needs to edit them, but all other operations on them will be pure data analysis and read-only. The entities will also be persisted, read and updated by an ORM, and will serve as models in the MVVM pattern.

What bothers me is that these entities will be passed around heavily, and I would like to protect them from unintentional modifications of their properties in code.

First of all - is implementing any type of protection worth it? Unintentional modifications will only happen in case of a programmer error/poor usage of the class. Maybe the entities should be left fully mutable, and the code well-documented and deemed safe as long as it is thoroughly covered by tests and passes them?

For educational purposes, suppose the protection from unintended changes is mandatory. How can I enforce it? Making the objects completely immutable and cloning them might pose difficulties when working with the ORM. Providing a simple mutable/immutable switch is misleading in a multithread context. Introducing immutable interfaces that expose a mutable object like in this answer doesn't enforce immutability, it just hides the objects - it is more explicit for a user of this code, but doesn't fully protect from a programmer error.

I'm using C# 5 and .NET Framework 4.5.

UPDATE

Okay, I have realized how little I know about domain driven design and its concepts. Anyway, based on the two answers in this thread I've came up with the following design:

  • There will be a repository class that hides the ORM and persistence logic. The ORM works with DTOs (all setters public, no validation, default constructor). The users of the repository can't see the DTOs but are able to query immutable domain objects that the repository creates based on these DTOs.
  • For adding/editing entities, a viewmodel is created and its properties populated with values from the domain object. The viewmodel is fully mutable and has all the validation logic. On save, a new domain object is created with the values from the viewmodel, and then saved or updated through the repository.

For me, this poses two new questions. The immutable domain object represents a valid entity, thus all its values should be validated in the constructor. The viewmodel, on the other hand, can hold incorrect values, which are then validated (for example, in the IDataErrorInfo implementation). How do I avoid duplicating the validation logic between the view model and the domain object?

Second question - to store/update a domain object through the repository, I need to track the Id value from the DTO created by the ORM and set it in the domain object. What bothers me is that this is a strictly persistence detail and has no relevance in the business logic. Is it okay that this persistence detail seeps into the domain?

How reasonable is this design? Am I even thinking in the right direction?

up vote 4 down vote accepted

I would recommend mapping your DTOs to a domain object and make that domain object immutable

Just give it private setters and create it through a factory, instead of passing around the DTO all over.

Making it immutable is definitely not a bad idea if you think it should be immutable, documenting still has a risk that a new developer will enter the arena and make some initial mistakes. This is not the end of the world but you want to decrease software entropy as much as possible.

However, I would not recommend making your DTO immutable because you shouldn't have a need for it most of the time. It is a dumb, simple object that carries data, but domain object, on the other hand, can be immutable because it reflects real life requirements of the business.

  • Thanks. Please see the update to my question. Am I on the right track? – sdds Apr 8 '15 at 13:27
  • 1
    @sdds 1) Make validation a domain service first of all if you haven't already. View model shouldn't validate anything. The view model will pass data back to the domain and it will be validated in the domain. Wheather it is going to the view model or coming back from it. Validation is all in the domain. 2) If you look at it actually it IS a domain concern for your objects to be unique because otherwise you wouldn't care about the order when saving them. Something in the domain requires them to be unique. At least that's what I see so having unique ids should be fine. – AvetisG Apr 8 '15 at 14:50

The entities will also be persisted, read and updated by an ORM, and will serve as models in the MVVM pattern.

Why?

I mean, you basically came out and said that you'd like your entity (as used by the business logic and used by the ORM) to be immutable, but that you'd like your model (as used by the UI) to be mutable (at least for the add/edit screen).

So decouple those two things, like they should've been in the first place.

  • Thanks for the answer. Please see the update to my question. Am I on the right track? Also, shouldn't the entities used by the ORM be mutable? – sdds Apr 8 '15 at 13:26
  • @sdds - only if the ORM requires it, or it makes your life much better. Otherwise, my general instinct is to be immutable by default. – Telastyn Apr 8 '15 at 13:45
  • Right, I meant that the mutability of entities used by the ORM is determined by the ORM's requirements. Would you mind taking a look at the update to my question and give your thoughts on the design I came up with? – sdds Apr 8 '15 at 14:49

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.