It's a domain model but also mapped to some table in the database via the mapping configuration done by FluentNHibernate.
I don't think this is a good idea. You are trying to do three (or maybe four) things in this one class that I would keep separate.
I recommend having a DTO for NHibernate (maybe called CarDto
) and a business model (probably called Car
). That way, CarDto
can change for reasons related to the database (but not for modeling reasons) and Car
can change for modeling reasons (but not for database reasons). For example, functional programming would have the business model be immutable, but NHibernate may require that its DTOs are mutable. If you use the same type for both purposes, then you can't satisfy all the design constraints.
how do I map the Sunroof property using its backing field knowing that they don't share the same return type?
I don't think you should have a property and a backing field with different types. With CarDto
, use null
to represent the absence of a Window
. Then when mapping from CarDto
to Car
, map null
to the None
state (via the Optional
function that you are currently using). Then when mapping from Car
to CarDto
, map None
back to null
(via the IfNoneUnsafe
method that you are currently using).
Your Car
class
- is NHibernate's DTO,
- is your business model,
- contains the mapping from the DTO to the business model, and
- contains the mapping from the business model to the DTO.
This is the three or four things (depending on if you count the mapping as one thing or two) that I mentioned above.
ADDED 2019-02-20
[your answer is] not a solution to my problem but a proposal for a better architecture
It is both.
I fully agree with what you said and I would be very happy to do that but I can't. In my code base I have more than 250 model classes which are quite badly designed and with a lot of wrongly made dependencies. I can't afford to refactor all of that at once.
I am not suggesting that you change everything at once. Far from it. In the style of Refactoring by Martin Fowler, I recommend making many small changes over time.
For example, how difficult would it be to change Car
to
public class Car
{
Option<Window> Sunroof
{
get => Optional(SunroofBacking);
set => SunroofBacking = value.IfNoneUnsafe((Window) null);
}
Window SunroofBacking { get; set; }
}
and use (the "better" named) property Sunroof
for business logic reasons and use SunroofBacking
for NHibernate
reasons?