2

It seems private setters inside classes that entity models inherit from cause bizarre issues with EFCore migrations. Consider the following example, where there are multiple classes (Bar and Baz) that inherit from Foo. When running Add-Migration commands multiple times (add/remove the private modifier`), the generated schema is just wrong in multiple ways.

  • Sometimes the Created property is set to be a dropped column
  • Sometimes all the the Created properties are set to be removed (and not replaced/renamed with anything).

It's my understanding that EFCore tools don't really treat properties with private setters with any special care. Is this a wrong assumption? If so, why do some private setters work on base classes, but not others? I'm assuming this is a bug in the EF Tools, perhaps related to how it treats naming on properties, considering I have other properties with similar names in the model which might be confusing the tools

public class Context : DbContext
{
    public DbSet<Bar> Bars { get; set; }
    public DbSet<Baz> Bazs { get; set; }
}

public class Bar : Foo { }
public class Baz : Foo { }
public abstract class Foo
{
    protected Foo()
    {
        Created = DateTimeOffset.UtcNow;
    }
    public DateTimeOffset? Created { get; private set; }
    public DateTimeOffset? Updated { get; set; }
}

Edit -> It seems private setters for DateTimeOffset cause EF Tools to never map them in base classes. However, I have a string property with a private setter with [Required] and [StringLength] attributes, along with builder.Entity<Foo>().HasAlternateKey(x => x.RequiredStringProperty); In that case, EF absolutely maps the property...but only with some of the classes that are inheriting from Foo.

Brad M
  • 7,857
  • 1
  • 23
  • 40
  • I couldn't find a case when the `private` setter works. Also can't find a documentation stating that, but looks like properties w/o setters or with private setters are considered not mapped by default. – Ivan Stoev Dec 21 '16 at 15:05
  • @IvanStoev They are sometimes definitely being mapped. I just ran another migration test, except I added `builder.Entity().HasAlternateKey(x => x.Created);` In my project, one of the `Bars` wanted to drop the column Created, but not the `Baz`. To be more specific, the property doing this is a string with the `[Required]` and `[StringLength]` attribute. Somehow the behavior is different than `DateTimeOffset?` – Brad M Dec 21 '16 at 15:20

1 Answers1

1

The EF core tools will map private setters of base classes only under certain conditions.

For example, if you have builder.Entity<Bar>().HasAlternateKey(x => x.Created);, then EF tools will map the Created property regardless of whether it has a private or public setter.

Brad M
  • 7,857
  • 1
  • 23
  • 40
  • 1
    Same if you have `builder.Entity().Property(x => x.Created);`. That's why I said *by default* in my first comment. Basically any fluent accessor to the property (except `Ignore` of course) is causing it to be mapped regardless of the private setter. Frankly I would avoid private setters (protected and internal setters have no such default behavior). Btw, I don't think this is tools behavior, but EF infrastructure default mapping. – Ivan Stoev Dec 21 '16 at 15:52