简体   繁体   中英

Entity Framework 6.1 and Member Hiding using New Keyword

I have a bunch of entities that implement an interface called ICreatableEntity . The definition is:

public interface ICreatableEntity {
    int CreatedById { get; set; }
    Employee CreatedBy { get; set; }
    DateTime CreatedDateTime { get; set; }
}

One specific entity, Employee , needs a slight modification because the very first record can't have a creator and thus I need to make the column nullable. So, I just tried to hide the inherited member using the new keyword like:

public new int? CreatedById { get; set; }

And it all works, the compiler likes it and all, but when the model is being generated by EF, it crashes with an error that the item already exists in the metadata collection . I'm guessing, EF probably adds my override in first, then proceeds to add the base property as well, even though I'm trying to hide it, and that's when it crashes.

Update: I have tried to leave it as is and in the Fluent API configuration change it to Optional, which also compiles fine, but crashes yet again when my seed data is being inserted because I still leave it effectively null.

Is there a workaround for this that doesn't require me to flip the logic and make it nullable for everything, and then add dozens of Fluent API configurations to tell EF it's actually required everywhere else?

Update: Just to give a little bit more information, the database is being regenerated every time by EF since I'm not using anything preexisting.

I found a solution that I'm quite content with. It hit me that when specifying a foreign key I can use either HasForeignKey() or Map() with the Fluent API. HasForeignKey() requires you to specify an already existing property on the entity, but Map() allows you to specify the name of the property EF will generate for you as the foreign key. Since prior to using either methods the relationship will already be configured as required or optional ( HasRequired() , HasOptional() ), the nullability will be account for.

So, I just did that and removed the explicit property declarations from my interfaces which auto-magically resolved the entire issue I was having. It also helped that I started using a base configuration class that does a lot of the heavy lifting for the entities that implement my interfaces. I just had to override a specific method once for the Employee configuration and it was good to go.

Here's a shortened version of the base configuration class that made things happen.

internal class Configuration<TEntity> :
    EntityTypeConfiguration<TEntity>
    where TEntity : class, ICreatableEntity, new() {
    protected virtual void Configure() {
        this.Configure(ConfigurationParameters.Default);
    }

    protected virtual void Configure(
        ConfigurationParameters parameters) {
        this.ConfigureCreatableRelationships(parameters.CreatedByWillCascadeOnDelete);
    }

    #region Relationship Configurations
    protected virtual void ConfigureCreatableRelationships(
        bool willCascadeOnDelete) {
        this.HasRequired(
            t =>
                t.CreatedBy).WithMany().Map(
            m =>
                m.MapKey("CreatedById")).WillCascadeOnDelete(willCascadeOnDelete);
    }
    #endregion
}

And the override in my EmployeeConfiguration class:

internal sealed class EmployeeConfiguration :
    Configuration<Employee> {
    protected override void ConfigureCreatableRelationships(
        bool willCascadeOnDelete) {
        this.HasOptional(
            t =>
                t.CreatedBy).WithMany().Map(
            m =>
                m.MapKey("CreatedById"));
    }
}

I hope this helps someone in the future.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM