2

NHibernate can be extended with new implementations of IUserType, so I can customize how a mapped property is read and stored to/from the database.

An example. If I want DB null varchar to load as "n/a" string, and "n/a" string to be stored as null.

How is this possible with EF 6.2?

I am looking for a solution that doesn't break the change-tracker.

Stig
  • 1,974
  • 2
  • 23
  • 50
  • Is there somehing like `HasConversion` in EF 6 as there is in EF core? – cantSleepNow Mar 05 '21 at 14:46
  • Unfortunately not. But I was hoping for some low level hook, that I could use to mimic this extension (HasConversion) – Stig Mar 10 '21 at 16:22
  • well, if you can't go to EF core, then you could take a look into how this HasConversion is implemented there and maybe do the same for EF (non-core ) – cantSleepNow Mar 10 '21 at 16:46
  • @cantSleepNow If this could be done by extending the code, fine by me. If I need to alter the EF code, this is a no go. – Stig Mar 10 '21 at 17:06

1 Answers1

2

As of EF 6.2, there is no such functionality provided out of the box by the library.

If you decide to move to EF Core instead, there you can use the HasConversion functionality.

However, in your case you still wouldn't be able to use it, because there is one caveat: it can't be used to convert null values. Null always gets converted to null. From docs:

A null value will never be passed to a value converter. A null in a database column is always a null in the entity instance, and vice-versa. This makes the implementation of conversions easier and allows them to be shared amongst nullable and non-nullable properties. See GitHub issue #13850 for more information.

In that case, I suggest that instead of a Value Conversion you configure your string property to have a Backing Field. Then, you can read/write to/from the private backing field, and then have a public property handling the null value.

public class Blog
{
    private string _stringFromDb;

    public string MyString { get; set; }

    [BackingField(nameof(_stringFromDb))]
    public string MyString
    {
        get { return _stringFromDb ?? "n/a"; }
    }

    public void SetMyString(string myString)
    {
        // put your validation code here

        _stringFromDb = myString;
    }
}

In EF 6.2 the closest you could have, as a workaround, is a [NotMapped] property that can be in charge of translating the property you load from the DB.

public string StringDB { get; set; }

[NotMapped]
public string StringConverted
{ 
    get { return MyStringProperty ?? "n/a"; }
    set { MyStringProperty = value  }
}

If, in addition to this, you want to hide the property being mapped to your DB by making it private, it's not as straightforward as with EF Core's backing field, but you could follow this other answer for instructions on how to achieve it.

dglozano
  • 6,369
  • 2
  • 19
  • 38
  • Thanks, but this a is no go, as this will clutter our domain model. I need a hook in EF to control the mapping logic. And yes this is EF6.2 only. – Stig Mar 10 '21 at 16:17
  • Actually the NotMapped is our current solution, but I need to get away from this :) If only I could use Nhibernate :) – Stig Mar 10 '21 at 16:24
  • @Stig I understand, but EF 6 doesn't have that functionality unfortunately, so there is no way, and they are not planning to add it either (ref. https://github.com/dotnet/ef6/issues/710) – dglozano Mar 10 '21 at 16:33
  • 1
    +1 for answer from me. @Stig you should really try hard and epxplain to your PO/SM/CTO/CEO or whoever decides on this that sooner or later you will have to move from EF to EFCore, not only for this reason (conversions) but many other adnvatages (just look at EFCore5) – cantSleepNow Mar 10 '21 at 16:49
  • Thanks @dglozano and your are positive that there is not any low level hook, I can use? – Stig Mar 10 '21 at 17:07
  • @Stig you are welcome :) I can't say I am a 100% positive that there isn't any low level API that you could use because I am far from knowing all EF internals, but at least I have never heard of anything like it, nor it's documented, nor it was mentioned by the mantainers in the Github issue linked above. So even if it existed, I would (personally) not use such low level API in those conditions – dglozano Mar 10 '21 at 17:59
  • 1
    And as @cantSleepNow , I would consider moving to EF Core as well :) We have ported a big application from EF 6 to EF Core 3.1, and it wasn't nearly as bad as I first expected. It should be even easier now that EF Core 5 supports Many to Many relations – dglozano Mar 10 '21 at 18:02