I am using Enitity Framework codefirst and I have the following design
public class Location
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsDeleted { get; set; }
}
public class DelieryRate
{
public int Id { get; set; }
public int OriginId { get; set; }
public Location Origin { get; set; }
public int DestinationId { get; set; }
public Location Destination { get; set; }
public double Amount { get; set; }
public bool IsActive { get; set; }
}
I do not want to define the relationship on Location. When I update the database, it works but I get a referential integrity error when I run my seed code. I have tried to configure it using fluent api as follows
modelBuilder.Entity<DeliveryRate>()
.HasRequired(e => e.Origin)
.WithOptional()
.WillCascadeOnDelete(false);
modelBuilder.Entity<DeliveryRate>()
.HasRequired(e => e.Destination)
.WithOptional()
.WillCascadeOnDelete(false);
When attempting to update the database I get the following error
System.Data.Entity.Infrastructure.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.UpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.ConstraintException: Referential integrity constraint violation. A Dependent Role has multiple principals with different values. --- End of inner exception stack trace --- at System.Data.Mapping.Update.Internal.TableChangeProcessor.DiagnoseKeyCollision(UpdateCompiler compiler, PropagatorResult change, CompositeKey key, PropagatorResult other) at System.Data.Mapping.Update.Internal.TableChangeProcessor.ProcessKeys(UpdateCompiler compiler, List
1 changes, Set
1 keys) at System.Data.Mapping.Update.Internal.TableChangeProcessor.CompileCommands(ChangeNode changeNode, UpdateCompiler compiler) at System.Data.Mapping.Update.Internal.UpdateTranslator.d__0.MoveNext() at System.Linq.Enumerable.d__711.MoveNext() at System.Data.Mapping.Update.Internal.UpdateCommandOrderer..ctor(IEnumerable
1 commands, UpdateTranslator translator) at System.Data.Mapping.Update.Internal.UpdateTranslator.ProduceCommands() at System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, IEntityAdapter adapter) at System.Data.EntityClient.EntityAdapter.Update(IEntityStateManager entityCache) at System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options) at System.Data.Entity.Internal.InternalContext.SaveChanges() --- End of inner exception stack trace --- at System.Data.Entity.Internal.InternalContext.SaveChanges() at System.Data.Entity.Internal.LazyInternalContext.SaveChanges() at System.Data.Entity.DbContext.SaveChanges() at System.Data.Entity.Migrations.DbMigrator.SeedDatabase() at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.SeedDatabase() at System.Data.Entity.Migrations.DbMigrator.Upgrade(IEnumerable1 pendingMigrations, String targetMigrationId, String lastMigrationId) at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.Upgrade(IEnumerable
1 pendingMigrations, String targetMigrationId, String lastMigrationId) at System.Data.Entity.Migrations.DbMigrator.Update(String targetMigration) at System.Data.Entity.Migrations.Infrastructure.MigratorBase.Update(String targetMigration) at System.Data.Entity.Migrations.Design.ToolingFacade.UpdateRunner.RunCore() at System.Data.Entity.Migrations.Design.ToolingFacade.BaseRunner.Run() An error occurred while updating the entries. See the inner exception for details
Is there a better way to model the relationship between Locations and DeliveryRate. Am I making a mistake with the fluent api bit
One-to-one relationships with separate foreign keys are not supported by Entity Framework. EF maps your model with shared primary keys, that is DeliveryRate.Id
, DeliveryRate.Origin.Id
and DeliveryRate.Destination.Id
must all have the same value. They probably have not in your Seed
method which is the cause of the exception.
Shared primary keys are not useful for your model because you could never create a DeliveryRate
that has a Destination
different from Origin
.
You can solve the problem by modeling the two relationships as one-to-many:
modelBuilder.Entity<DeliveryRate>()
.HasRequired(e => e.Origin)
.WithMany()
.HasForeignKey(e => e.OriginId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<DeliveryRate>()
.HasRequired(e => e.Destination)
.WithMany()
.HasForeignKey(e => e.DestinationId)
.WillCascadeOnDelete(false);
This error is thrown when there is a mistake in relationship mapping, it could be mapping two reationships to the same foreign key property:
modelBuilder.Entity<TipOrder>().HasRequired(c => c.Tip).WithMany(x => x.TipOrders).HasForeignKey(x => x.TipId).WillCascadeOnDelete(false);
modelBuilder.Entity<TipOrder>().HasRequired(c => c.Order).WithMany(x => x.TipOrders).HasForeignKey(x => x.TipId).WillCascadeOnDelete(false);
both map, accidently, to TipId.