Mario
Mario

Reputation: 988

EF Core multiple navigation properties produce circular dependency

I have the following mapping configuration:

Entry-Class:

entity
    .HasOne(e => e.CurrentHandling)
    .WithOne()
    .HasForeignKey<Entry>(e => e.CurrentHandlingID)
    ;

entity
    .HasMany(e => e.Handlings)
    .WithOne(h => h.Entry)
    .HasForeignKey(h => h.EntryID)
    ;

Handling-Class:

entity
    .HasOne(h => h.Entry)
    .WithMany(e => e.Handlings)
    .HasForeignKey(h => h.EntryID)
        .OnDelete(Microsoft.EntityFrameworkCore.Metadata.DeleteBehavior.Restrict);

ERM: enter image description here

When I try to save the context I get the following exception:

System.InvalidOperationException: 'Unable to save changes because a circular dependency was detected in the data to be saved: 'ForeignKey: Entry.CurrentHandlingID -> Handling.HandlingID Unique ToPrincipal: CurrentHandling, ForeignKey: Handling.EntryID -> Entry.EntryID ToDependent: Handlings ToPrincipal: Entry'.'

Test-Data:

errorRepo.EnableBulkModus();

var handling = errorRepo.AddHandling(new Handling {
     CorrectedMessage = "correct",
     HandlingStatusID = 7,
     Updated = DateTime.UtcNow,
     UpdatedBy = nameof(DbInitializer)
});

var reference = errorRepo.AddReference(new Reference {
    ForeignKeyTypeID = 4,
    ForeignKeyValue = "42",
    Name = "SystemB",
    ReferenceTypeID = 6
});

var entry = errorRepo.AddEntry(new Entry {
    CurrentHandling = handling,
    DisplayMessage = "Wrong!",
    ErrorMessage = "error!",
    Inserted = DateTime.UtcNow.AddMinutes(-5),
    OriginalMessage = "incorrect",
    InsertedBy = nameof(DbInitializer),
    UUID = Guid.NewGuid(),
    Reference = reference,
    StatusID = 5
});

handling.Entry = entry;
entry.Handlings.Add(handling);

errorRepo.DisableBulkModus(true);

errorRepo.EnableBulkModus(); sets just a flag which indicates the repository not to save when calling CommitChanges() Same with errorRepo.DisableBulkModus(true);, it sets the flag to false. The boolean indicated, that the repository should perform a CommitChanges().

How do I have to change my mapping to avoid a circular dependency?

kind Regards.

EDIT (11.03.2017)

I removed the mapping from the Handling-Class and added the line .OnDelete(Microsoft.EntityFrameworkCore.Metadata.DeleteBehavior.Restrict) in the Entry-Class:

    entity
        .HasMany(e => e.Handlings)
        .WithOne(h => h.Entry)
        .HasForeignKey(h => h.EntryID)
        .OnDelete(Microsoft.EntityFrameworkCore.Metadata.DeleteBehavior.Restrict)
        ;

Same exception:

System.InvalidOperationException: 'Unable to save changes because a circular dependency was detected in the data to be saved: 'ForeignKey: Entry.CurrentHandlingID -> Handling.HandlingID Unique ToPrincipal: CurrentHandling, ForeignKey: Handling.EntryID -> Entry.EntryID ToDependent: Handlings ToPrincipal: Entry'.'

Upvotes: 5

Views: 3136

Answers (1)

Gert Arnold
Gert Arnold

Reputation: 109347

See this:

// 1.
var entry = errorRepo.AddEntry(new Entry {
    CurrentHandling = handling,
    ...
});
...
// 2.
handling.Entry = entry;

The code below 1. requires entry to receive handling's primary key as foreign key. The code below 2. requires handling to reveive entry's primary key as FK: a chicken-and-egg problem.

Since handling depends on entry (because of the 1-0..1 relationship), entry should be inserted first --not having its CurrentHandling property set yet. Then save changes, so entry knows its generated PK. Then set entry.CurrentHandling and handling.Entry and save changes again.

You may want to wrap this code in a transaction.

By the way, the line entry.Handlings.Add(handling); is redundant.

Upvotes: 9

Related Questions