Base solution for your next web application
Open Closed

Update Child entities when updating parent #9723


User avatar
0
dougmorato created

We have just started developing a new product using ASPNetZero 9.1 Angular version. But I have doubts regarding the CRUD operation of entities with multiple parent-child relations.

We have a “Parent” entity that contains a collection of “Child” entities. The “Child” table has the foreign key of parent ID.

Now as per the requirement when updating parent user update/delete any existing child or add a new child.

By following the Tutorial, I have tried with the below code. But it is throwing error “Child cannot be tracked because another instance with the same key value for {'Id'}”

<br>

protected virtual async Task Update(CreateOrEditParentDto input)
{
var parent = await _parentRepository.GetAllIncluding(v => v.children)
.FirstOrDefaultAsync(v => v.Id == (int)input.Id);
ObjectMapper.Map(input, parent);
}

<br> I have tried insert, delete children within for loop. But that is also throwing error.  I have found multiple links similar kind of issue but none of the solutions able to fix this issue.

What is the best way to add/update/delete all child entities with the same transaction?  A similar code works perfectly for the insert.


9 Answer(s)
  • User Avatar
    0
    zony created
    Support Team

    Hi dougmorato, The problem is caused by repeated tracking of entities. Can you upload the code definition of CreateOrEditParentDto? And the code for the parent entity and child entity?

  • User Avatar
    0
    dougmorato created

    Please find the sample code below.

    `public class CreateOrEditParentDto : EntityDto&lt;int?&gt; { 		
    [Required] 		public string ParentName { get; set; } 	
    public ICollection&lt;CreateOrEditChildDto&gt; Children { get; set; } }`
    
     public class CreateOrEditChildDto : EntityDto<int?>
        {
    		[Required]
    		public string Email { get; set; }
    		public string FirstName { get; set; }
    		public string LastName { get; set; }
    		public int ParentId { get; set; }
    }
    

    The core classes are like below

     [Table("Parent")]
        public class Parent : FullAuditedEntity , IMustHaveTenant
        {
    		public int TenantId { get; set; }
    		[Required]
    		public virtual string ParentName { get; set; }
    		public virtual ICollection<Child> Children { get; set; }
    }
    
    [Table("Child")]
        public class Child : FullAuditedEntity , IMustHaveTenant
        {
    	   public int TenantId { get; set; }
    		[Required]
    		public virtual string Email { get; set; }		
    		public virtual string FirstName { get; set; }		
    		public virtual string LastName { get; set; }
    		public virtual int ParentId { get; set; }	
             [ForeignKey("ParentId")]
    		public Parent ParentFk { get; set; }
    	}
    
  • User Avatar
    0
    zony created
    Support Team

    Okay, I will try to reproduce the problem.

  • User Avatar
    0
    zony created
    Support Team

    Hi dougmorato, I wrote the following code, but cannot reproduce your problem. Entities

    [Table("Demo.Grade")]
    public class Grade : FullAuditedEntity
    {
        [Required]
        [StringLength(128)]
        public string Name { get; set; }
    
        public virtual ICollection<Student> Students { get; set; }
    }
    
    [Table("Demo.Student")]
    public class Student : AuditedEntity<int>
    {
        [Required]
        [StringLength(128)]
        public string Name { get; set; }
    
        public int GradeId { get; set; }
    
        [ForeignKey("GradeId")]
        public virtual Grade Grade { get; set; }
    }
    

    DTOs

    public interface IDemoEntityAppService : IApplicationService
    {
        Task CreateAsync(GradeCreateDto input);
    
        Task UpdateAsync(GradeCreateDto input);
    }
    
    public class GradeCreateDto : EntityDto<int>
    {
        [Required]
        [StringLength(128)]
        public string Name { get; set; }
    
        public List<ChildEntityDto> Students { get; set; }
    }
    
    public class ChildEntityDto : EntityDto<int>
    {
        [Required]
        [StringLength(128)]
        public string Name { get; set; }
    
        public int GradeId { get; set; }
    }
    

    Service

    public class DemoEntityAppService : ApplicationService, IDemoEntityAppService
    {
        private readonly IRepository<Grade> _repository;
    
        public DemoEntityAppService(IRepository<Grade> repository)
        {
            _repository = repository;
        }
    
        public async Task CreateAsync(GradeCreateDto input)
        {
            var entity = ObjectMapper.Map<Grade>(input);
            await _repository.InsertAsync(entity);
        }
    
        public async Task UpdateAsync(GradeCreateDto input)
        {
            var parent = await _repository
                .GetAllIncluding(x => x.Students)
                .FirstOrDefaultAsync(x => x.Id == input.Id);
    
            ObjectMapper.Map(input, parent);
        }
    }
    

  • User Avatar
    0
    dougmorato created

    You will get the same error if you inherit the child table from FullAuditedEntity. By following your code I have also changed the child table and it working then. But I need the audit columns, soft delete in the child table also.

    Also in your code, if we delete a child object from child collection it is not affecting the database. But if we updating any child property is reflecting in the database. Should we have to manually identify deleted children and then delete those within a loop by calling the delete method of child repository?

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi @dougmorato

    EF Core doesn't work well in such situations. We introduced Abp.GraphDiff pacakge for such operations. You can try to use it or, better, you can manually update each child entity in a foreach loop.

  • User Avatar
    0
    dougmorato created

    But the main issue is not resolved . You will get the same error if you inherit the child table from FullAuditedEntity. The sample you have provide the child is inheriting from AuditedEntity<int> not FullAuditedEntity.

  • User Avatar
    0
    dougmorato created

    Have you got any any solution? I need FullAuditedEntity in child tables also. But the application is throwing error during update.

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi @dougmorato

    Could you share your final AppService class ? I assume your entity definitions are still like this https://support.aspnetzero.com/QA/Questions/9723/Update-Child-entities-when-updating-parent#answer-0a8bc52b-da78-fee8-cb01-39f82b2f5a5b. I will take a look at this again.

    Thanks,