I’ve recently learned the functional programming approach for C#, so I’m on the lookout to make my code more functional and my objects more immutable. I’m also starting a new ASP.NET MVC Core + EF Core personal project as part of my #CodeNewbie training journey. Of course, I wanted to put these things together: functional programming and ASP.NET+EF.
At first, I was hoping to use the new record type with positional parameters. However, the docs explicitly state that record types and immutable objects are not suitable for Entity Framework. It makes sense because the Entity Framework ORM is used to interact with a database — and a database is mutable, state-full data storage. On a side note: if you’re careful, Entity Framework will let you use constructors with parameters.
Of course, I tested these theories in my code. I broke Entity Framework by making my properties immutable with { get; init; }
. Sure enough, it didn’t work. Entity Framework prefers to create our objects with a parameterless constructor and then use public setters when performing CRUD operations.
Then, I was so happy to find an article that encouraged private setters and StackOverflow answers that encouraged private setters for Id fields. After all, if the database sets the primary key then my code shouldn’t need to worry about that. I made private setters for my Id fields, manually tested a few pages of my app, and all seemed great…
Until a couple days later when I had an unexpected side effect when working on another commit. Only the HttpPost Edit methods on my Controller classes wouldn’t work. After an hour of debugging, it turns out that ASP.NET MVC Binding also needs a public setter for the Edit method to bind the Id property. As you can see in the screenshot below, ModelState was valid – but the object (basicShape) had an incorrect BasicShapeId value of 0 (it should have been 1). In this case, a validation check caught it and I was getting a 404 Page Not Found error. Without that check, Entity Framework would have been adding new rows to the database every time I submitted the Edit form (because _DbContext.SaveChanges() will add a new row if the object has an Id of 0). Removing the private
keyword from the setter fixed the problem.
Turns out that even though Entity Framework can use private setters, and ASP.NET’s Model Binding cannot. And they both need mutable objects.
On another note, this story is a good example of the importance of unit tests. They would have caught this bug at the time it was introduced and saved me a tricky debugging session. Thankfully, unit testing is the next item to learn on my training journey. Now I’m really, really looking forward to it!