EFCore: ошибка ассоциации сущностей во время простого обновления свойства

Я хотел бы установить одно свойство bool в своем контроллере и сохранить его в базе данных. EF выдает ошибку о других свойствах, которые даже не изменены.

Связь между сущностями «Пользователь» и «RequestDetail» с ключевым значением «System.InvalidOperationException»: связь между сущностями «Пользователь» и «RequestDetail» со ​​значением ключа «{Id: 40}» разорвана, но связь либо помечен как «Обязательный» или неявно требуется, поскольку внешний ключ не допускает значения NULL. Если зависимая / дочерняя сущность должна быть удалена при разрыве требуемой связи, настройте связь для использования каскадного удаления.

Если я вызываю свой метод с дополнительным параметром, он должен изменить свойство RequestSent одной записи RequestDetail, и это отлично работает. Но вызывая метод без этого дополнительного параметра, он должен изменить это свойство более чем для одной записи RequestDetail. И вот тут возникает ошибка. Я не изменяю ничего, связанного с User. Если ему нужно сделать больше записей одновременно, он выдает эту ошибку. Даже если я переписываю foreach на некоторое время с помощью FirstOrDefaults () и немедленного SaveChanges (), он выдает ошибку во втором раунде.

Мой метод:

var head = await _ctx.RequestHeads.FirstOrDefaultAsync(x=>x.Id == d.Id);
if (!d.DetailId.HasValue) {
            var details = _ctx.RequestDetails.Include(x=>x.BuyerUser)
                            .Where(x=>x.RequestHeadId == head.Id); 
//not working, always throws an error if it has to modify more than one record
            await details.ForEachAsync(detail => {
                detail.RequestSent = true;
            });
        } else {
            var detail = head.Details.FirstOrDefault(x=>x.Id == d.DetailId.Value); //works ok, always
            detail.RequestSent = true;
        }
        await _ctx.SaveChangesAsync();

Мои модели:

public class RequestHead
{
    [Key, MaxLength(15)]
    public string Id { get; set; }
    public DateTime CreateDate { get; set; }
    public int CreateUserId { get; set; }
    [ForeignKey("CreateUserId")]
    public User CreateUser { get; set; }

    public DateTime? AcceptDate { get; set; }
    public int? AcceptUserId { get; set; }
    [ForeignKey("AcceptUserId")]
    public User AcceptUser { get; set; }

    public DateTime? CloseDate { get; set; }
    public int? CloseUserId { get; set; }
    [ForeignKey("CloseUserId")]
    public User CloseUser { get; set; }     
    public int? CloseReason { get; set; }   
    public bool IsArchive { get; set; }

    [MaxLength(8)]
    public string OrganizationCode { get; set; }

    [ForeignKey("OrganizationCode")]
    public Organization Organization { get; set; }

    public virtual ICollection<RequestDetail> Details { get; set; }
    public virtual ICollection<RequestAttachment> Attachments { get; set; }
}

public class RequestDetail
{
    [Key]
    public int Id { get; set; }

    public string RequestHeadId { get; set; }

    [ForeignKey("RequestHeadId")]
    public RequestHead RequestHead { get; set; }

    [MaxLength(20)]
    public string ProductCode { get; set; }

    [ForeignKey("ProductCode")]
    public Product Product { get; set; }
    public string ProductName { get; set; }
    public bool NoProductCode { get; set; }
    public string Description { get; set; }
    public DateTime CreateDate { get; set; }
    public int CreateUserId { get; set; }
    [ForeignKey("CreateUserId")]
    public User CreateUser { get; set; }


    public DateTime? DelegateDate { get; set; }
    public int? DelegateUserId { get; set; }
    [ForeignKey("DelegateUserId")]
    public User DelegateUser { get; set; }


    public int? BuyerUserId { get; set; }
    [ForeignKey("BuyerUserId")]
    public User BuyerUser { get; set; }

    public bool RequestSent { get; set; }
    public virtual ICollection<RequestAttachment> Attachments { get; set; }

}

Контекст:

modelBuilder.Entity<RequestHead>()
            .HasOne(r=>r.CreateUser)
            .WithOne().OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<RequestHead>()
            .HasMany(r => r.Details)
            .WithOne(x=>x.RequestHead)
            .HasForeignKey(rd => rd.RequestHeadId);
modelBuilder.Entity<RequestDetail>()
            .HasOne(r=>r.CreateUser)
            .WithOne().OnDelete(DeleteBehavior.Restrict);

person Perrier    schedule 26.07.2018    source источник
comment
Не уверен, связаны ли они, но два .WithOne() в User отношениях выглядят очень подозрительно. Вероятно, они должны быть .WithMany(). Другое отличие состоит в том, что нерабочий запрос содержит .Include(x=>x.BuyerUser).   -  person Ivan Stoev    schedule 26.07.2018
comment
@IvanStoev Include (x = ›x.BuyerUser) был просто тестом, если проблема могла быть в том, что свойства навигации не загружаются. Хорошая точка зрения на .WithOne (), однако, я уверен, что это должно быть что-то в моей конфигурации контекста. Спасибо!   -  person Perrier    schedule 26.07.2018
comment
@IvanStoev Вы решили это, WithOne () вызвал проблему. Однако я не совсем понимаю, почему он был выдан только при одновременном изменении нескольких записей и что было за сообщением об ошибке?   -  person Perrier    schedule 26.07.2018
comment
Что ж, большинство сообщений EF ... сбивают с толку :) Я могу с этим жить (у них много функциональных задач, поэтому я думаю, что сообщения имеют самый низкий приоритет). Что касается поведения, я думаю, что при однозначном коде ожидает одна запись, поэтому, когда приходит вторая запись с тем же FK, они запутались и решили, что запись удалена :) Просто предположение - фактический код довольно сложно.   -  person Ivan Stoev    schedule 26.07.2018
comment
@IvanStoev Не могли бы вы опубликовать это в качестве ответа, чтобы я мог закрыть эту проблему?   -  person Perrier    schedule 26.07.2018
comment
Нет времени сочинять хороший ответ. Пожалуйста, не стесняйтесь публиковать самостоятельный ответ. Рад, что помог, удачного кодирования.   -  person Ivan Stoev    schedule 26.07.2018


Ответы (1)


Решением было изменить RequestDetail ‹=> Пользовательские отношения с WithOne () на WithMany (). Хотя сообщение об ошибке несколько вводит в заблуждение, возможное объяснение от @IvanStoev следующее:

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

person Perrier    schedule 26.07.2018