Domanda

I have an entity called Employee. It has a nullable property called CreatedById which is used as a reference back to itself. It has to be null since the very first record, presumably the administrator, won't have a creator. When by database is being initialized, I keep getting an error when the first Employee object is inserted which I presume is because of the way I updated the relationships with the Fluent API. Code is as follows:

The Employee class:

public class Employee : NullableInt32Entity, IUser<int> {
    /// Omitted code that doesn't matter
}

The NullableInt32Entity class that Employee inherits from:

public class NullableInt32Entity :
    Entity,
    ICreatableEntity<int?>,
    IIndexableEntity<int> {
    #region ICreatableEntity Members
    public int? CreatedById { get; set; }
    #endregion

    #region IIndexableEntity Members
    public int Id { get; set; }
    #endregion
}

The configuration in the EmployeeConfiguration class that I think is causing the issue:

this.HasOptional(
    t =>
        t.CreatedBy).WithOptionalPrincipal();

The DatabaseInitializer class:

internal sealed class DatabaseInitializer : DropCreateDatabaseIfModelChanges<DatabaseContext> {
    protected override void Seed(
        DatabaseContext context) {
        Employee creator = new Employee {
            FirstName = "System",
            IsActive = true,
            LastName = "Administrator",
            PasswordHash = "AIw9zIWiDnIesTaYhSjJhHJo5VYWCUV1rH0Oa0TaTriQXiDmXDBSq5y8Q0Zv3KUw/Q=="
        };

        context.Employees.Add(creator);
        context.SaveChanges();

        /// Additional seeds that depend on the one above as their creator.
    }
}

And last, but not least the exception I'm getting: Entities in 'DatabaseContext.Employees' participate in the 'Equipment_CreatedBy' relationship. 0 related 'Equipment_CreatedBy_Source' were found. 1 'Equipment_CreatedBy_Source' is expected.

So, my question is, how do I fix this? I started using WithOptionalPrincipal() and WithRequiredPrincipal() today for the first time because I realized I don't care for navigational properties from Employee to any of the other objects. I used to have a XCreated collection navigation property in Employee for every other object and I realized that they were pointless to expose since I'll never use them. Thus I stripped them out and had to use the methods above.

I appreciate any suggestions, and thanks in advance!

È stato utile?

Soluzione

Ok, so it turns out I'm the idiot here. @KirillBestemyanov in one of his comments said that it was the Equipment entity that was causing the issue. That's when it all clicked in my head because I was reading, but not understanding the error message. I had it in my head that the Employee entity was the cause when it wasn't. I was also using the wrong configuration when I was using the WithOptionalPrincipal() and WithRequiredPrincipal() methods. I wasn't understanding how they functioned.

The code in the second comment above was in fact correct, but again, I was applying it to the wrong entity which wasn't at fault which is why the error wasn't getting resolved. Understanding where I had gone wrong, I went on a rewrite spree for my entire DbContext implementation. I now have a much more robust implementation and its Maintainability Index went from 60 to 76, which I'm happy about.

I implemented two base classes which helped me resolve my issues, here's the code in case someone is interested in the future:

Configuration_TEntity class

internal abstract class Configuration<TEntity> :
    EntityTypeConfiguration<TEntity>
    where TEntity : class, ICreatableEntity, IRemovableEntity, new() {
    protected virtual void Configure() {
        this.ConfigureCreatableProperties();
        this.ConfigureRemovableProperties();
        this.ConfigureProperties();
        this.ConfigureCreatableRelationships();
        this.ConfigureRemovableRelationships();
        this.ConfigureRelationships();
    }

    #region Property Configurations
    protected virtual void ConfigureCreatableProperties() {
        this.Property(
            p =>
                p.CreatedDateTime).HasColumnType("datetime2");
    }

    protected virtual void ConfigureRemovableProperties() {
        this.Property(
            p =>
                p.RemovedDateTime).HasColumnType("datetime2");
    }

    protected abstract void ConfigureProperties();
    #endregion

    #region Relationship Configurations
    protected abstract void ConfigureCreatableRelationships();

    protected virtual void ConfigureRemovableRelationships() {
        this.HasOptional(
            t =>
                t.RemovedBy).WithMany().HasForeignKey(
            k =>
                k.RemovedById);
    }

    protected abstract void ConfigureRelationships();
    #endregion
}

Configuration_TEntity_TCreatedByKey class

internal class Configuration<TEntity, TCreatedByKey> :
    Configuration<TEntity>
    where TEntity : class, ICreatableEntity, ICreatableEntity<TCreatedByKey>, IRemovableEntity, new()
    where TCreatedByKey : struct {
    protected override void ConfigureCreatableRelationships() {
        this.HasRequired(
            t =>
                t.CreatedBy).WithMany().HasForeignKey(
            k =>
                k.CreatedById);
    }

    protected override void ConfigureProperties() {
    }

    protected override void ConfigureRelationships() {
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top