As I learn more and more from Domain Driven Design, my classes for DDD projects (those that are complex enough to need more than simple CRUD), are shifting from what are referred to as “anemic domain models” and more like “rich domain models”.
The term “anemic domain model” (which I still have an aversion to…the term, that is) refers to a class that doesn’t really do much at all. It has a bunch of properties and maybe some methods. To use them you instantiate or retrieve the object and then populate the properties at will. When working in DDD, the focus is on behaviors, not properties. So you would have methods to control what happens to your objects and in doing so, constrain the properties so that they are not exposed to be set or modified “willy nilly”.
Here is an extremely simple pair of classes that are designed using some of the techniques I’m learning from DDD:
public class AThingAsEntity { private AThingAsEntity(){} //the private constructor public AThingAsEntity(string description, int anInt, string aString) { Description = description; SomeOtherThing = new SomeOtherThing(anInt, aString); } public int Id { get; private set; } public string Description { get; private set; } public SomeOtherThing SomeOtherThing { get; set; } public void TheOtherThingMustChange(int anInt, string aString) { SomeOtherThing = new SomeOtherThing(anInt, aString); } }
public class SomeOtherThing:ValueObject<SomeOtherThing> { private int anInt; private string aString; private SomeOtherThing(){} //the private constructor
//this value object’s constructor is internal to prevent random instantiation
internal SomeOtherThing(int anInt, string aString) { AValue = anInt; AnotherValue = aString; } public int AValue { get; private set; } public string AnotherValue { get; private set; } }
I’m constraining the class so that anyone who instantiates it is required to pass in some values. And those values all have private setters. There’ s no way to write code like:
var thing=new AThingAsEntity(); thing.Description="oh i'll just put whatever I want in here. heh heh heh. Domain rules be damned";
That’s the way I want to write this class to represent my domain.
In the past week or so, I’ve been asked three separate times (by three different developers) if it’s possible to use this pattern of private setters with EF. The answer is “yes”. Here, let the Doctor confirm that:
And in case you’re curious, I’m doing this with EF5.
Entity Framework requires a parameterless constructor in order to materialize objects returned from queries (or loading). I have made this concession in my class but notice that it is a private constructor. So I’m still protecting my class. Nobody can access it. But EF is still able to populate this class when I execute queries. And no, I’m not doing some magic to tell EF to use my public constructor. It really uses the private constructor.
I’ll use an integration test to demonstrate.
Note that my test is using an initializer called SeedMyThings to always drop and recreate the database and shove in this seed data:
new AThingAsEntity("This is MY thing", 42, "That is the meaning of life")
My test sets that initializer so I can perform the test I’m interested which requires some seed data.
[TestClass] public class Tests { public Tests() { Database.SetInitializer(new SeedMyThings()); } [TestMethod] public void EfCanPopulateObjectWithPrivateCtorAndSetters() { using (var context=new ThingieContext() ) { var thing = context.Things.FirstOrDefault(); Assert.IsInstanceOfType(thing,typeof(AThingAsEntity)); Assert.AreNotEqual(0, thing.Id); Assert.IsFalse(string.IsNullOrEmpty(thing.Description)); Assert.IsFalse(string.IsNullOrEmpty(thing.SomeOtherThing.AnotherValue)); } } }
I know…all those Asserts…bad tester. So shoot me. 😉
Anyhooooo…. the test passes. Even with my private ctor and private setters, EF is able to materialize the object and even it’s SomeOtherThing property which is a value object. (which also has a private ctor and private setters). Internally EF is reading the metadata of the model and using reflection to set the values of the properties.
I also want to point out that I had been using a protected constructor. In the past, I am sure I tried private and it didn’t work. (Maybe an earlier version of EF?) But Steve Smith asked me “if setters work as private, why not constructor?” So I tried it and voila, it worked too.
And now, for my first EVER public Git repository. You can find my little sample solution at https://github.com/julielerman/EF_and_Private_CTORs_n_Setters. 🙂