3
votes

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, List1 changes, Set1 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(IEnumerable1 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(IEnumerable1 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

2

2 Answers

4
votes

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);
0
votes

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.