Comments 21
Всё конечно здорово. Статья до последнего держит в напряжении и не раскрывает главную загадку - о какой собственно библиотеке речь?
Не совсем понятен смысл изобретения велосипеда, когда полно альтернатив автомапперу - и через рефлексию, и через кодогенерацию. Тот же Mapster.
Производительность. Соотношение производительности к геморою использования у этой либы очень неплох
Из бенчмарков что я смотрел mapperly самый производительный, и по скорости + аллокациям практически идентичен мапингу ручками. AutoMapper значительно уступал.
Я тоже не использую AutoMapper предпочитая явное неявному. Но пример автора, как мне кажется, неудачный, стоило упростить код, оставив только то, что относиться к заявленной теме.
Было бы достаточно следующего:
public class Projection<TSource, TResult>
{
private readonly Lazy<Func<TSource, TResult>> _lazyDelegate;
public Projection(Expression<Func<TSource, TResult>> expression)
{
Expression = expression;
_lazyDelegate = new Lazy<Func<TSource, TResult>>(Expression.Compile, LazyThreadSafetyMode.PublicationOnly);
}
internal Expression<Func<TSource, TResult>> Expression { get; }
internal Func<TSource, TResult> Delegate => _lazyDelegate.Value;
public TResult Map(TSource source) => Delegate(source);
}
public static class ProjectionExtensions
{
public static IQueryable<TDestination> Projection<TSource, TDestination>(
this IQueryable<TSource> queryable, Projection<TSource, TDestination> projection)
{
return queryable.Select(projection.Expression);
}
public static IEnumerable<TDestination> Projection<TSource, TDestination>(
this IEnumerable<TSource> enumerable, Projection<TSource, TDestination> projection)
{
return enumerable.Select(projection.Delegate);
}
}
Полный код с рабочим примером:
https://gist.github.com/Zerg903/007967724a9d37f19856b083a1b6bf6e
Такой подход не даст использовать проекцию в проекции, мне такая возможность нужна, кому-то конечно будет и без нее хорошо (в этом и есть плюс самого подхода).
public static readonly Projection<SubCategory, SubCategoryDetails> SubCategoryDetails = new(x => new SubCategoryDetails
{
Id = x.Id,
Active = x.Active,
// тут вложенная проекция:
Category = CategoryLookupDetails.ProjectTo(x.Category),
Name = x.Name,
Description = x.Description,
CreatedDate = x.CreatedDate,
ModificationDate = x.ModificationDate
});
Кроме того, есть случаи когда хотелось бы задать отдельное поведение для делегата, например, при использовании DbFunctions
.
Вот я отвечал на StackOverflow: Can I reuse code for selecting a custom DTO object for a child property with EF Core?. Как на меня это самый удобный способ работать без Automapper. DelegateDecompiler так вообще упрощает это дело в разы.
Как-то упускается супер полезная фича у автомаппера как валидация конфигурации. В процессе активной разработки мне юнит тесты часто сыпят ошибки что новые поля не замаплены
После недолгого использования AutoMapper и отпыта более опытных людей, также пришли в выводу что "ручномаппер" удобнее во всех отношениях (:
Ручной маппер это полный контроль, что не может не радовать. Чем меньше магии, тем лучше. Но чем больше кода пишешь, тем чаще ловишь себя на мысли, что довольно много времени занимаешь тупым обезьяньим трудом. Трудом, который способна сделать за нас машина. Т.е. с одной стороны, мы автоматизируем работу людей с помощью разработки ПО. С другой стороны, как сапожник без сапог, жмём много кнопок там, где можно было бы их не жать.
Мы проверили как в старой рекламе на свеженьком небольшом проекте, just for fan. Примерно половину проекта писали на ручном маппинге. Вторую половину на Mapster-е в режиме "маппинг на пределе". Результаты. На второй половине проекта, разработка ведётся ощутимо быстрее. Меньше ошибок, ощутимо! Особенно при развитии модели данных. Больше времени посвящается интересным задачам, просто дышится легче.
Т.е., резюмируя, контроль это здорово! Каждый байт под учётом, каждая буква. И да, по опыту работы с AutoMapper иногда случалась необходимость решить сложный маппинг, который "на ручнике" просто бы писался как есть, и такие мысли возникали, может ну его? Но на длительной дистанции, обезьяний труд зло.
Автомаппер для бедных