Search code examples
c#architectureprinciples

How could virtual properties in model classes violate the persistence ignorance principle?


I've just read (revised) some architectural principles (as documented here https://learn.microsoft.com/en-us/dotnet/architecture/modern-web-apps-azure/architectural-principles) and felt a bit confused about the persistence ignorance principle having a violation example like this:

 Properties requiring virtual keyword

So I don't get it clearly why such a requirement could violate the persistence ignorance principle. Provided that our model classes are just in C#, compiled by .NET compiler. To load a model instance, just create the class instance normally (with all properties initialized from the corresponding persistent data, e.g: a data record). To save it just read the values from the model instance and put it back to persistent storage (of any kind).

Actually Entity Framework does have that requirement to enable some cool features such as lazy loading, … And I do see that EF has been doing its great job to support various kinds of persistent storage (databases), which as I understand should be contrary to the so-called a violation of the persistence ignorance principle.

Could you give me some real-world example to demonstrate that requiring virtual properties could violate the persistence ignorance principle? If any present, isn't that sometimes we could not just comply with all the principles and we may have to take some trade-offs to balance between following good principles and having nice features (as in case of EF ?


Solution

  • The reason it violates the persistence ignorance principle is very simple: you have to make the properties virtual to make EF happy, so you changed the business code duo to a persistence concern. And besides directly violating the principle, using features of EF that override members of your class change the type of the class, so, for example, in your Equals implementation, you cannot use GetType() anymore to compare the two instances, as the actual type of the object is generated by EF at runtime, so again, you start to change your domain logic according to persistence concerns. On a side note, I would also advise against using EF's lazy loading in most cases, because it only works synchronously, blocking the current thread.