问题
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!
回答1:
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() {
}
}
来源:https://stackoverflow.com/questions/23176881/entity-framework-6-1-savechanges-fails-with-optional-principal-relationship