Frage

I just implemented explicitly loading child entities along with their parents using in a generic repository using jevelez's method shown in this question.

However now i'm trying to map the child entities along with their parent entities to DTO's so i can send them to my UI layer.

Here's how my mappers currently look like:

The mapping interface:

public interface IMappingService<TEntity, TDto>
    where TEntity : class 
    where TDto : class
{
    TDto EntityToDto(TEntity entity);
    TEntity DtoToEntity(TDto dto);
    IEnumerable<TDto> EntitiesToDtos(IList<TEntity> entities);
    IEnumerable<TEntity> DtosToEntities(IList<TDto> dtos);
}

The abstract base method that implements the interface:

public abstract class MapperBase<TEntity, TDto> : IMappingService<TEntity, TDto>
    where TEntity : class 
    where TDto : class
{
    public abstract TDto EntityToDto(TEntity entity);

    public abstract TEntity DtoToEntity(TDto dto);

    public virtual IEnumerable<TDto> EntitiesToDtos(IList<TEntity> entities)
    {
        return entities.Select(EntityToDto);
    }

    public virtual IEnumerable<TEntity> DtosToEntities(IList<TDto> dtos)
    {
        return dtos.Select(DtoToEntity);
    }
}

Here's are two mappers that implement these for two entities as an example:

public class ParentEntityMapper : MapperBase<ParentEntity, ParentEntityDto> , IParentEntityMapper
{

    private readonly IChildEntityMapper _childEntityMapper;

    public ParentEntityMapper(IChildEntityMapper  childEntityMapper)
    {
        _childEntityMapper = childEntityMapper;
    }

    public override ParentEntityDto EntityToDto(ParentEntity entity)
    {
        var dto = new ParentEntityDto();
        dto.Id = entity.Id;
        dto.Title = entity.Title;
        dto.Description = entity.Description;

        if (entity.ChildEntities != null)
        {
            dto.ChildEntities= _childEntityMapper.EntitiesToDtos(entity.ChildEntities .ToList()).ToList();
        }

        return dto;
    }

    public override ParentEntity DtoToEntity(ParentEntityDto dto)
    {
        // This is just a reverse of the above function
    }
}

And the child entity mapper:

    public class ChildEntityMapper : MapperBase<ChildEntity, ChildEntityDto>, IChildEntityMapper
    {
        private readonly ParentEntityMapper _parentEntityMapper;

        public ChildEntityMapper(IParentEntityMapper parentEntityMapper)
        {
            _parentEntityMapper = parentEntityMapper;
        }
        public override ChildEntityDto EntityToDto(ChildEntity entity)
        {
            var dto = new ChildEntityDto();

            dto.Id = entity.Id;
            dto.Description = entity.Description;

            if (entity.ParentEntity != null)
            {
                dto.ParentEntity = _parentEntityMapper.EntityToDto(entity.Image);
            }

            return dto;
        }

        public override Anchor DtoToEntity(AnchorDto dto)
        {
            // Just a reverse of the above function
        }
    }

So i sure you all can see where the circular dependency occurs. I've been agonizing over this for the past 2 days but I'm still pretty amateur at this and haven't been able to figure this out using Google thus far.

I prefer not to use tools like AutoMapper and ValueInjector for this part since i'm mapping between the database and DTO's and I'm already using it to map between the DTO's and the ViewModels in the UI layer.

If possible I'd like to be able to keep the mapping between the two this way since sometimes I'll be requesting just the child entities and in those cases I might want to get the parent entity along with it.

Does anyone know how this can be done properly?

War es hilfreich?

Lösung 2

After thinking about it further i decided that instead of over complicating it that i would'nt allow getting a child entity with it's parent through the mapper but instead handle it for those few but specific scenarios in my service layer.

Anyone having the same problem can also check this thread i created on reddit for more information.

Andere Tipps

I think I see where your "circular dependency" is coming in to play here, but just to be explicit, here's what I think would happen. You call EntityToDto on the ParentEntity, which in turn calls EntityToDto on all of the ChildEntity elements. Each of these ChildEntity elements in turn call EntityToDto on the ParentEntity and we are back to where we started from.

If that's the case my recommendation would be simple: don't have the child entity care EntityToDto on the parent. I would resolve at the root of the tree and then let everything below continue to resolve downward until the tree is complete.

If you did it this way, it would prevent the child entity from assigning the parent to itself. If you need to be able to traverse from the child to the parent, I'd have the parent assign itself to the child as the parent after the EntityToDto call was complete.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top