Base solution for your next web application
Open Closed

Aggregate root #4956


User avatar
0
mentium created

Hi

I have an large graph I theat like an aggregare root, how does aggregate root work in abp zero, can it update (add, update, delete) the whole graph?


3 Answer(s)
  • User Avatar
    0
    alper created
    Support Team

    Hi,

    It's not completely aggregate root friendly.

    When you insert an entity with children it'll insert the entity and children. There's no problem with that. But when you update that entity it'll update the master entity, plus it'll add new children without deleting the excluded ones.

    To explain it let's give an example; You create Person with 2 phone numbers. This will result as 1 Person in persons table and 2 phones in Phones table. And incremental ID of the person

    var person = await _personRepository.InsertAsync(new Person
     {
                    Name = "aggregate",
                    Surname = "root",
                    EmailAddress = "[email protected]",
                    Phones = new List<Phone>
                    {
                         new Phone { Number = "1111"},
                         new Phone { Number = "2222"}
                     }
     });
    var personId = person.Id; //let's assume we get 23 as an incremental Id.
    

    Now you update the person (which is Id of 23). You update name,surname, emailAddress fields and you add 2 different phone numbers except the ones persisted in database. While the user will be updated in database as you want, you'll see 4 records in Phones table. It'll not update the existing ones. (even you set the Id fields of the children EF is not tracking the children). So you need to manually insert the new ones, delete the removed ones and update the existing ones.

    await _personRepository.UpdateAsync(new Person
     {
                Id = 23, //personId which is 23.
                Name = "aggregate2",
                Surname = "root2",
                EmailAddress = "[email protected]",
                Phones = new List<Phone>
                {
                           	 new Phone { Number = "4444", Id=118}, //even you set the IDs, entity framework will not update these...
                           	 new Phone { Number = "5555", Id=119}
                 }
    });
    
  • User Avatar
    0
    mentium created

    Hi @alper

    Thanks for your answer.

    It could be nice to have a generic tool to handle that.

    Today i'm using my own function to map from aggregate root dto to entity, but when it is more than one level i have to write a lot of code to handle it.

    protected void UpdateNavigationProps<TKye, TDto, TEntity>(List<TDto> dtos, ICollection<TEntity> entities)
                where TEntity : Entity<TKye>, new()
                where TDto : EntityDto<TKye>
            {
                if (dtos == null)
                    return;
    
                if (entities == null)
                    entities = new List<TEntity>();
    
                foreach (var entity in entities.ToList())
                {
                    if (!dtos.Any(c => c.Id.Equals(entity.Id)))
                    {
                        //Remove
                        entities.Remove(entity);
                    }
                }
    
                foreach (var dto in dtos)
                {
                    var entity = entities.FirstOrDefault(p => p.Id.Equals(dto.Id) && !p.Id.Equals(default(long)));
                    if (entity == null)
                    {
                        //Add
                        entities.Add(ObjectMapper.Map<TEntity>(dto));
                    }
                    else
                    {
                        ObjectMapper.Map(dto, entity);
                    }
                }
            }
    
  • User Avatar
    0
    alper created
    Support Team

    I think you did a good job.