Как каскадно обновлять отношения один-ко-многим в ef-core - PullRequest
0 голосов
/ 31 января 2020

У меня есть отношение многие к одному от таблицы ApiApplicant до таблицы Api. Моя таблица Api имеет следующие поля: Api: ID, имя, дата, isDeleted ApiAppliant: Id, ApiID, ApplicantId, ApiRequestDate, gateId, isDeleted. ApiId - это внешний ключ в ApiApplicant для таблицы Api. Теперь моя проблема состоит в том, что если пользователь хочет удалить запись Api, только значение isDeleted должно быть изменено на 1., а затем в таблице ApiApplicant связанные записи, имеющие тот же ApiId, также должны иметь значение isDeleted, равное 1. Я новичок в ef-core и asp. net. Я буду признателен, если кто-нибудь предложит мне решение, показав пример кода.

1 Ответ

0 голосов
/ 03 февраля 2020

Вы можете переписать метод SaveChangesAsync в DbContext, чтобы обновить значение isDeleted как в родительском, так и в дочернем объектах. Также не забудьте отключить каскадное удаление ядра EF.

См. Следующие шаги:

1.Модели:

public class Api
{
    [Key]
    public int ID { get; set; }

    //other properties

    public bool isDeleted { get; set; }
    public List<ApiApplicant> ApiApplicants { get; set; }
}

public class ApiApplicant
{
    [Key]
    public int Id { get; set; }
    public int? ApiID { get; set; }//set as nullable

    //other properties

    public bool isDeleted { get; set; }
    [ForeignKey("ApiID")]
    public Api Api { get; set; }
}

2.DbContext (отключить каскадное удаление по умолчанию)

public class ApplicationDbContext : IdentityDbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }

    public DbSet<Api> Apis { get; set; }
    public DbSet<ApiApplicant> ApiApplicants { get; set; }


    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {

        modelBuilder.Entity<Api>()
                    .HasMany(i => i.ApiApplicants)
                    .WithOne(c => c.Api)
                    .OnDelete(DeleteBehavior.Restrict);
    }

    public override int SaveChanges(bool acceptAllChangesOnSuccess)
    {
        OnBeforeSaving();
        return base.SaveChanges(acceptAllChangesOnSuccess);
    }

    public override Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default(CancellationToken))
    {
        OnBeforeSaving();
        return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
    }

    private void OnBeforeSaving()
    {


        foreach (var entry in ChangeTracker.Entries())
        {
            if (entry.State == EntityState.Deleted)
            {
                if (entry.Entity is Api )
                {
                    entry.State = EntityState.Modified;
                    //change Api.isDeleted value to true
                    entry.CurrentValues["isDeleted"] = true;

                    //change navigations' isDeleted value to true
                    foreach (var c in entry.Collections)
                    {
                        if(c.Metadata.Name == "ApiApplicants")
                        {
                            foreach (var item in (IEnumerable)c.CurrentValue)
                            {
                                    ((ApiApplicant)item).isDeleted = true;
                            }
                        }

                    }

                }
            }
        }
    }
}

3. Удалить действие

[HttpPost]
public async Task<IActionResult> DeleteConfirmed(int id)
    {
        var api = await _context.Apis.Include(a => a.ApiApplicants).FirstOrDefaultAsync(a=>a.ID == id);
        _context.Apis.Remove(api);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }
...