cezarypiatek / MappingGenerator

:arrows_counterclockwise: "AutoMapper" like, Roslyn based, code fix provider that allows to generate mapping code in design time.
https://marketplace.visualstudio.com/items?itemName=54748ff9-45fc-43c2-8ec5-cf7912bc3b84.mappinggenerator
MIT License
1.03k stars 120 forks source link

Question: Complex expression mapping #95

Closed rmszc81 closed 4 years ago

rmszc81 commented 4 years ago

Consider the following models:

namespace ModelMapping.Application
{
    public class Person
    {
        public Guid Id { get; set; }
        public string Name { get; set; }
    }
}

namespace ModelMapping.Domain
{
    public class Person
    {
        public Guid Id { get; set; }
        public string Name { get; set; }
    }
}

how can I map the following expression?

static Expression<Func<IQueryable<Domain.Person>, IOrderedQueryable<Domain.Person>>> MyFunction(Expression<Func<IQueryable<Application.Person>, IOrderedQueryable<Application.Person>>> expression) { }

I use this expression like this:

Expression<Func<IQueryable<Application.Person>, IOrderedQueryable<Application.Person>>> expression = persons => persons.OrderBy(p => p.Name);

Thank you.

cezarypiatek commented 4 years ago

Hi

I'm not sure what exactly you want to achieve but you can take a look at this issue https://github.com/cezarypiatek/MappingGenerator/issues/34 Generating a mapping expression should be supported. MappingGenerator is generating recursive mappings so I would suggest paying special attention to the mapping of related entities in order to avoid n+1 problem when you are operating on IQueryable<>

Please let me know if the solution proposed in #34 solves your problem.

rmszc81 commented 4 years ago

Hi @cezarypiatek,

No, issue #34 doesn't solve my problem at all.

What I need to map, beyond models are Where expressions such as

Expression<Func<SourceModel, bool>>

and Queryable expressions, such as

Expression<Func<IQueryable<SourceModel>, IOrderedQueryable<SourceModel>>>

to generate in short the mappings for:

Expression<Func<TargetModel, bool>> // and 
Expression<Func<IQueryable<TargetModel>, IOrderedQueryable<TargetModel>>>

In short, what I have today with AutoMapper is:

CreateMap<Expression<Func<Domain.Model.Person, bool>>, Expression<Func<Repository.Model.Person, bool>>>();
// and
CreateMap<Expression<Func<IQueryable<Domain.Model.Person>, IOrderedQueryable<Domain.Model.Person>>>, Expression<Func<IQueryable<Repository.Model.Person>, IOrderedQueryable<Repository.Model.Person>>>>();

How can I create these mappings using your tool?

I want to get rid of AutoMapper too, it's causing me a lot of trouble with these mappings. In short I'm trying to make my research project less dependent as possible from 3rd party frameworks and AutoMapper is one of them. Autofac is the next, lol.

Thanks.

cezarypiatek commented 4 years ago

Can you provide an example of code that should be generated?

rmszc81 commented 4 years ago

@cezarypiatek, I have no idea, I just use AutoMapper to map between the expressions from my Application to Domain models just to transport lambda queries, such as where and order by, for example:

// where
person => person.Age >= 18;

// order by
persons => persons.OrderBy(person => person.Name);

I'm sorry, I'm really no expert on Mapping expressions.

Thanks,

[],

cezarypiatek commented 4 years ago

I guess there are three hidden operations performed under the hood by AutoMapper:

The first two (filtering and sorting) you have to do by yourself and the third one (select()) can be generated by MappingGenerator. The mapping expression it's the exact thing that #34 explains.

In your case, the example code can looks as follows

IEnumerable<ModelMapping.Domain> SimulateAutoMapperMagic(IContext<ModelMapping.Domain> input)
{
    return input.Where(person => person.Age >= 18)
        .OrderBy(person => person.Name)
        .Select(/* Here comes the expression generated by MappingGenerator */)
        .ToList();
}
cezarypiatek commented 4 years ago

@rmszc81 can you confirm that my previous commend did or did not answer your question? Is there anything else that I can help you with?

rmszc81 commented 4 years ago

@cezarypiatek sorry, I really forgotten to answer you.

yes, your answer solve a part of my problem but, as my project is working extensively based on the generics technique, I'm being forced to use a framework for this time.

I will research more and see what I can do. For now, I will close the thread since my question is not really easy to answer due to my needs.

Thank you very much!

Regards,

[],

@rmszc81