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?