Automapper: Simple condition with ProjectTo doesn't work

Created on 26 Mar 2020  路  8Comments  路  Source: AutoMapper/AutoMapper

Hello. I have the problem with ProjectTo.
I have that Select map:

var posts = await appContext.Posts
    .Select(x => new PostListReadModel()
    {
        IsAnonymous = x.IsAnonymous,
        Publisher = !x.IsAnonymous ?
            new PostPublisherReadModel()
            {
                Id = x.PublisherId,
                Nick = x.Publisher.Nick,
                PhoneNumber = x.Publisher.PhoneNumber,
                Avatar = x.Publisher.Avatar
            } :
            null
    })
    .ToListAsync();

As you can see, I have a mapping condition for the Publisher property. Very simple condition.
It translates to sql like this:

SELECT p.IsAnonymous, NOT (p.IsAnonymous), p.PublisherId, u.Nick, u.PhoneNumber, i.Id, i.DateCreated, i.DateUpdated, i.FileName
      FROM posts AS p
      INNER JOIN users AS u ON p.PublisherId = u.Id
      LEFT JOIN images AS i ON u.AvatarId = i.Id

And it works.

Now, I want to use ProjectTo. And I have a map configuration like this:

CreateMap<User, PostPublisherReadModel>();

CreateMap<Post, PostListReadModel>()
    .ForMember(dest => dest.IsAnonymous, opt => opt.MapFrom(src => src.IsAnonymous))
    .ForMember(dest => dest.Publisher, opt => opt.Condition(src => !src.IsAnonymous))
    .ForAllOtherMembers(opt => opt.Ignore());

It translates to sql like this:

SELECT p.IsAnonymous, FALSE, i.Id, i.DateCreated, i.DateUpdated, i.FileName, u.Id, u.Nick, u.PhoneNumber
      FROM posts AS p
      INNER JOIN users AS u ON p.PublisherId = u.Id
      LEFT JOIN images AS i ON u.AvatarId = i.Id

and it naturally doesn't work.

Is it an automapper error or am i doing something wrong?

Question

All 8 comments

I think this is better suited for StackOverflow.

I think this is better suited for StackOverflow.

I asked a question on SO:
https://stackoverflow.com/questions/60881865/simple-condition-with-projectto-doesnt-work

The very simple explanation is that the condition you have in your Select expression isn't the same as our condition. Our condition is roughly:

// precondition
if (typeMap.PreCondition(src), dest)
{
    var srcValue = GetSrcValue(src);
    var destValue = GetDestValue(dest);
    if (typeMap.Condition(src, dest, srcValue, destValue)
    {
        dest.SetValue(srcValue);
    }
}

Whereas you have a conditional operator ?:. That's a single expression. We do an if, you have an if/else.

As a rule of thumb, anything configuration method that accepts Expression<> is supported in LINQ, anything that accepts Func<> does not.

HOWEVER, it does seem that EF Core supports this. If we were to support it, we'd need a new overload, something like:

Condition(Expression<Func<TSource, bool>> condition, Expression<Func<TSource, TMember>> ifFalse)

HOWEVER, it does seem that EF Core supports this. If we were to support it, we'd need a new overload, something like:

So, should I wait in the future to fix the problem or not?

Based on the discussion in that issue, we do support what you're looking for. Just not with Condition. You need a MapFrom with that conditional operator in it. Condition is for "not mapping" not "have 2 paths for a map"

Based on the discussion in that issue, we do support what you're looking for. Just not with Condition. You need a MapFrom with that conditional operator in it. Condition is for "not mapping" not "have 2 paths for a map"

Before writing here, I tried this:
.ForMember(dest => dest.Publisher, opt => opt.MapFrom(src => !src.IsAnonymous ? src.Publisher : null)
and it failed

@bretbas then let's open a separate issue for that. MapFrom breaking is different than Condition.

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings