EF Core DeleteBehavior.Cascade может вызывать циклы или несколько каскадных путей. - PullRequest
0 голосов
/ 07 октября 2019

У меня есть следующие сущности (которые сокращены для краткости);

public class Trader : AuditableEntity
{
    public int? UserId { get; set; }
    public ApplicationUser User { get; set; }

    public int? AccountManagerId { get; set; }
    public ApplicationUser AccountManager { get; set; }

    public List<TraderContactHistory> ContactHistory { get; set; }
}

public class ApplicationUser : IdentityUser<int>, IEntity
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Level { get; set; }

    public DateTime JoinDate { get; set; }
    public DateTime? LastLogin { get; set; }

    public ApplicationUserImage ProfileImage { get; set; }
}

Просто для полноты TraderContactHistory выглядит следующим образом:

public class TraderContactHistory : Entity
{
    public Trader Trader { get; set; }
    public DateTime ContactDate { get; set; }
    public ApplicationUser ContactedBy { get; set; }
    public bool RequestedCallbackLater { get; set; }
    public string Notes { get; set; }
}

Теперь, после добавления изменения ограничения;

public override void Configure(EntityTypeBuilder<Trader> entity)
{
    entity.HasOne(x => x.User)
        .WithOne()
        .HasForeignKey<Trader>(x => x.UserId)
        .OnDelete(DeleteBehavior.Restrict);
}

к следующему (кактеперь у нас есть требование очистить соответствующего пользователя при удалении трейдера);

public override void Configure(EntityTypeBuilder<Trader> entity)
{
    entity.HasOne(x => x.User)
        .WithOne()
        .HasForeignKey<Trader>(x => x.UserId)
        .OnDelete(DeleteBehavior.Cascade);

    entity.HasOne(x => x.AccountManager)
        .WithMany()
        .HasForeignKey(x => x.AccountManagerId)
        .OnDelete(DeleteBehavior.SetNull);
}

и для полноты конфигурации TraderContactHistory:

    public override void Configure(EntityTypeBuilder<TraderContactHistory> entity)
    {
        entity.HasKey(x => x.Id);

        entity.HasOne(x => x.Trader)
            .WithMany(x => x.ContactHistory)
            .OnDelete(DeleteBehavior.Restrict);

        entity.HasOne(x => x.ContactedBy)
            .WithMany()
            .OnDelete(DeleteBehavior.Restrict);

    }

Создает следующую миграцию;

    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropForeignKey(
            name: "FK_Traders_AspNetUsers_UserId",
            schema: "Bemfeito",
            table: "Traders");

        migrationBuilder.AddForeignKey(
            name: "FK_Traders_AspNetUsers_UserId",
            schema: "Bemfeito",
            table: "Traders",
            column: "UserId",
            principalSchema: "Bemfeito",
            principalTable: "AspNetUsers",
            principalColumn: "Id",
            onDelete: ReferentialAction.Cascade);
    }

, которая вызывает следующую ошибку при запуске update-database (я работаю с базой данных MSSQL);

System.Data.SqlClient.SqlException (0x80131904): Введение ограничения FOREIGN KEY 'FK_Traders_AspNetUsers_UserId' в таблицу 'Traders' может привести к возникновению циклов или нескольких каскадных путей. Укажите ON DELETE NO ACTION или ON UPDATE NO ACTION, или измените другие ограничения FOREIGN KEY.

Может кто-нибудь увидеть, почему это генерируется? Может ли это быть TraderContactHistory, связанное с Trader, которое молча вызывает это? Как у меня в настоящее время нет конфигурации для него?

1 Ответ

1 голос
/ 07 октября 2019

Отношения внешних ключей в вашей модели данных выглядят следующим образом:

  • Trader -> * ApplicationUser
  • Trader -> * ApplicationUser
  • TraderContactHistory -> Trader
  • TraderContactHistory -> ApplicationUser

Таким образом, если вы удалите запись ApplicationUser, каскадное удаление удалит все записи Trader и все записи TraderContactHistory, указывающие на нее. Но удаление записи Трейдера, в свою очередь, также удалит некоторые элементы TraderContactHistory. Таким образом, у вас есть два пути каскадного удаления из ApplicationUser в TraderContactHistory:

  • TraderContactHistory -> ApplicationUser
  • TraderContactHistroy -> Trader -> ApplicationUser

и MSSQL не работаетэто не так. Я знаю, насколько это может раздражать, поверьте мне, так как мне приходится иметь дело с этим ограничением на регулярной основе.

При этом вы указали «Ограничить» в отношениях TraderContactHistory, что должно решить проблему. ,Может быть, фактическая схема не отражает это правильно?

Редактировать: Мне просто пришло в голову, что другие прямые отношения Trader-ApplicationUser могут быть виновником. Если Trader-AccountManager-dependency настроен как OnDelete Cascade, вы также получите несколько каскадных путей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...