Conflict with foreign key when the related entity is added before SaveChanges

c# entity-framework entity-framework-6

Question

If I attempt to add a linked object that doesn't exist at all, I anticipate EF 6.2.0 failing. But in this case, the problematic related entity (Person) is added to the context before SaveChanges (is not in the Db yet, but I see is in ChangeManager). But EF is saying to me, for some reason: "Conflict between the INSERT statement and the "FK AuditPerson Person" FOREIGN KEY constraint. The dispute happened in the "Person" database's "Person" table's "Id" field."

I've replicated my issue in a few classes:

public class Person
{
    public Guid Id { get; set; }
}

As well as:

public class AuditPerson
{
    public Guid AuditId { get; set; }
    public Guid PersonId { get; set; }
    public DateTime Timestamp { get; set; }
}

The situation is:

public class PersonTestContext : DbContext
{
    public DbSet<Person> Packages { get; set; }
    public DbSet<AuditPerson> PersonAudits { get; set; }

    public PersonTestContext() : base("PersonTestDb")
    {
        Database.SetInitializer<PersonTestContext>(null);
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Person>()
            .ToTable("Person", "person")
            .HasKey(t => t.Id);

        modelBuilder.Entity<AuditPerson>()
            .ToTable("AuditPerson", "dbo")
            .HasKey(ap => new { ap.AuditId, ap.PersonId });

        base.OnModelCreating(modelBuilder);
    }
}

The issue is shown by the following example:

    static void Main(string[] args)
    {
        using (var context = new PersonTestContext())
        {
            var person = new Person { Id = Guid.NewGuid() };
            context.Persons.Add(person);

            var audit = new AuditPerson { AuditId = Guid.NewGuid(), Timestamp = DateTime.UtcNow, PersonId = package.Id };

            context.PersonAudits.Add(audit);

            context.SaveChangesAsync().Wait();
        }
        Console.ReadKey();
    }

What other options are there to inform EF that PersonId refers to an object being saved during the same SaveChanges call?

When I add: the issue is now fixed.

public virtual Person Person { get; set; }

to the class AuditPerson. But is there any way that EF could handle this without a navigation property?

The "FK AuditPerson Person" already exists in the Db and is as follows:

ALTER TABLE [dbo].[AuditPerson]  WITH CHECK 
  ADD CONSTRAINT [FK_AuditPerson_Person] 
  FOREIGN KEY([PersonId])
  REFERENCES [person].[Person] ([Id])

Without a navigation feature, I feel like I have seen it done before.

last thoughts

Steve clarified that EF does not ensure the sequence of inserts. The entries are inserted without any FK conflicts if we apply the identical code but change the class name from Person to Appointment. The same thing happened with genuine production code (now fixed). Evidently, EF orders the inserts by class name, thus Person inserts come after Audits but Appointments come before, resulting in the observed behavioural discrepancy.

1
2
8/16/2018 7:59:07 AM

Accepted Answer

ZZZ_tmp
2
8/14/2018 6:41:19 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow