Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity framework Core : property setter is never called (Violation of encapsulation?)

In both EF Core and EF6, invoking the getter of the property 'Date' (see below) gives the correct value, however notice the slight difference between the two : in EF Core the setter is never called!

This is my model :

public class MyModel
{      
    private DateTime _Date;
    private bool dateTimeHasBeenSet = false;
    public DateTime Date
    {
        get
        {
            return _Date;
        }
        set
        {
            dateTimeHasBeenSet = true;
            _Date = value;
        }
    }
}

This is my way to retrieve a single item :

        //Entity Framework 6
        using (Ef6Context context = new Ef6Context())
        {

            var m =  context.MyModels.First();

            // m.dateTimeHasBeenSet is true

        }

        //Entity Framework Core
        using (EfCoreContext context = new EfCoreContext())
        {

            var m = context.MyModels.First();
            // m.dateTimeHasBeenSet is false
        }

Does EF core initialize the backup field instead of the property (through reflection)? doesn't this violate encapsulation?

I'm migrating some code from EF6 to EF Core and I really would like to avoid wasting time in manually invoking the logic behind each setter...

EDIT : Asking the question made me try something fancy, if I rename my backup field from _Property to any thing else like _PropertyX (In this example it would be _DateX) magically my setter is invoked by EF Core!

like image 287
Akli Avatar asked Nov 19 '17 22:11

Akli


1 Answers

With EF Core we have a notion of Backing Fields:

Backing fields allow EF to read and/or write to a field rather than a property.

When EF spot by convention a presence of a backing field for your property, it will use that field instead of your property when materializing your entity. Only after your entity is materialized and if EF need to update your entity it will use the property if possible (when the property is not readonly) otherwise it will continue to use your backing field.

You can tell, EF Core to always use your property when materializing your entity by doing the code below (only possible with Fluent API):

modelBuilder.Entity<MyModel>()
    .Property(b => b.Date)
    .HasField("_Date")
    .UsePropertyAccessMode(PropertyAccessMode.Property);

To learn more about Backing Fields go here.

If you want to apply this configuration to all properties in your model you can use UsePropertyAccessMode instance method of ModelBuilder like below:

modelBuilder.UsePropertyAccessMode(PropertyAccessMode.Property);
like image 185
CodeNotFound Avatar answered Nov 11 '22 13:11

CodeNotFound