Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make EF Core 2 work with a getter only property without a backing field

Tags:

My goal is to make Entity Framework 2 play nice with the following code:

public class Foo
{
    public Guid Id { get; } // This should NOT change

    public string NotRequiredProperty {get; set;}

    public Foo(Guid id) => Id = id;

    private Foo() { } // Empty constructor is necessary for EF Core I believe?
}

I have read this blog post that says the following can be done:

// Class
private Guid _id;
public Guid Id => _id;

// Configuration
modelBuilder.Entity<Foo>()
.Property(b => b.Id)
.UsePropertyAccessMode(PropertyAccessMode.FieldDuringConstruction);

Which COULD work.

The only improvement I see here is that I am required to explicitly declare a private backing field even though a { get; } means that one is created implicitly.

How can I make EF Core work with JUST a { get; } (and of course some required entity configuration)

like image 361
S. ten Brinke Avatar asked Jan 30 '19 15:01

S. ten Brinke


1 Answers

What you are asking is possible in general with EF Core 2.1 introduced Entity types with constructors with parameters feature. You don't need the empty constructor anymore - EF Core will be able to use the constructor with Guid id parameter.

However there are two limitations which apply to your Id property. First, it's a read-only property (hence is backed by readonly field which can be set only from a constructor). The equivalent in your explicit backing field example would be if you define it as private readonly Guid _id;. Then the sample configuration WON'T work.

The documentation section for Read-only properties says:

Once properties are being set via the constructor it can make sense to make some of them read-only. EF Core supports this, but there are some things to look out for:

  • Properties without setters are not mapped by convention. (Doing so tends to map properties that should not be mapped, such as computed properties.)
  • Using automatically generated key values requires a key property that is read-write, since the key value needs to be set by the key generator when inserting new entities.

Pay attention to the second bullet, because that's the second problem. The Id property by convention is a PK, and Guid and numeric type PKs by convention are auto-generated.

So you need to choose between two options - either make the Id non read-only by adding private set; as suggested in the link, or (which is the answer of the question "How can I make EF Core work with JUST a { get; }") make it non auto-generated by using the following fluent configuration:

modelBuilder.Entity<Foo>()
    .Property(e => e.Id)
    .ValueGeneratedNever();
like image 84
Ivan Stoev Avatar answered Sep 16 '22 17:09

Ivan Stoev