C#
C#

help

Root Question Message

FusedQyou
FusedQyou12/3/2022
❔ Unable to get automapper's projectTo() to work properly.

I need to use ProjectTo() to properly cast a query into a DTO, but in this case my user can only contains pictures which have Deleted = false. The code below works, but all photo's are returned, including deleted ones. The commented Include() works fine, but I need the mapping to happen on query level, and not after, because of the creation of a paginatedList. If I map later, the PaginatedList misses crucial information, and I do not want to change its behaviour.

public async Task<PaginatedList<DTODataUser>> GetAllDTOPaginatedAsync(PaginatedQuery pagination, bool includeDeleted, CancellationToken cancellationToken)
    {
        var userQuery = this._databaseContext
            .Users
            .Where(x => !includeDeleted ? !x.Deleted : true)
            .ProjectTo<DTODataUser>(this._mapper.ConfigurationProvider, null, (user) => user.Photos.Where(y => !includeDeleted ? !y.Deleted : true));
        //.Include(x => x.Photos.Where(y => !includeDeleted ? !y.Deleted : true))

        var users = await PaginatedList<DTODataUser>.CreateAsync(userQuery, pagination, cancellationToken);
        return users;
    }


How can I replicate Include to work with projectTo? As said above, the current version is allowed, but deleted photo's are returned too.
Angius
Angius12/3/2022
You do it in automapper's config
FusedQyou
FusedQyou12/3/2022
I just added .ExplicitExpansion(), but this did not change its behaviour
FusedQyou
FusedQyou12/3/2022
FusedQyou
FusedQyou12/3/2022
The conversion is DataUser -> DTODataUser
FusedQyou
FusedQyou12/3/2022
Am I missing something?
Angius
Angius12/3/2022
Huh
Angius
Angius12/3/2022
Honestly, that's why I dropped AutoMapper, way too much fuss
Angius
Angius12/3/2022
But I think that you can have a .Where() instead of that .ExplicitExpansion()..?
FusedQyou
FusedQyou12/3/2022
Yeah, but then I need a way to determine if the includeDeleted boolean is set
Angius
Angius12/3/2022
You can pass that to the mapper config
Angius
Angius12/3/2022
The way to do it is quite ugly, but there is a way
Angius
Angius12/3/2022
Again, one of the reasons I dropped it lol
FusedQyou
FusedQyou12/3/2022
Do/Can can you suggest an alternative?
Angius
Angius12/3/2022
Just a .Select()
Angius
Angius12/3/2022
If you need to reuse some mapping, make a class with static Expression<Func<TSource, TTarget>> properties and use those
FusedQyou
FusedQyou12/3/2022
Makes sense
FusedQyou
FusedQyou12/3/2022
After all it's just a lazy way of using it
FusedQyou
FusedQyou12/3/2022
But the reason why I need this is because PagedList inherits from List, and any properties in there are not serialized properly, and neither are they converted if I map later. I can also just fix this by not making it inherit from List
FusedQyou
FusedQyou12/3/2022
I do kinda want ProjectTo to just work properly because otherwise I get too much data, but oh well
FusedQyou
FusedQyou12/3/2022
I suppose I can still use a mapper outside of this service
Angius
Angius12/3/2022
static class UserMappings
{
    public static Expression<Func<User, UserDto>> ToDto = user => new UserDto {
        Name = user.UserName,
        Age = user.Age,
        Comments = user.Comments.Where(c => !c.IsDeleted)
    }

    
    public static Expression<Func<User, UserDto>> ToDtoWithParam(int param) => user => new UserDto {
        Name = user.UserName,
        Age = user.Age,
        Whatever = param > 10 ? user.Foo : user.Bae
    }
}
Angius
Angius12/3/2022
An example of doing the mappings with Expression<Func<,>>
Angius
Angius12/3/2022
Then just .Select(UserMappings.ToDto)
Angius
Angius12/3/2022
Not sure how that paginated list of yours works, so can't speak on that
Angius
Angius12/3/2022
Me, I just have a simple extension method for IQueryable
Angius
Angius12/3/2022
public static IQueryable<T> Paginate<T>(this IQueryable<T> query, int page, int perPage)
{
    if (page < 1)
        throw new ArgumentOutOfRangeException(nameof(page), "Page has to be greater than 0");
    if (perPage < 1)
        throw new ArgumentOutOfRangeException(nameof(perPage), "PerPage has to be greater than 0");

    return query
        .Skip(Math.Max(0, page - 1) * perPage)
        .Take(perPage);
}
ContactFrequently Asked QuestionsJoin The DiscordBugs & Feature RequestsTerms & Privacy