#c# #automapper
#c# #automapper
Вопрос:
Как мне избежать требования подобного кода:
public static class BusinessLogicAutomapper
{
public static bool _configured;
public static void Configure()
{
if (_configured)
return;
Mapper.CreateMap<Post, PostModel>();
_configured = true;
}
}
в моей сборке BL и необходимости вызывать Configure()
из моей Global.asax
в моем приложении MVC?
Я имею в виду, я ожидаю вызова, подобного этому:
public PostModel GetPostById(long id)
{
EntityDataModelContext context = DataContext.GetDataContext();
Post post = context.Posts.FirstOrDefault(p => p.PostId == id);
PostModel mapped = Mapper.Map<Post, PostModel>(post);
return mapped;
}
чтобы Mapper.Map<TIn,TOut>
создать mapper, если его не существует, вместо того, чтобы создавать его самому вручную (я даже не должен знать об этой внутренней работе). Как я могу обойти декларативное создание картографов для AutoMapper?
Было бы желательно решение, естественное для AutoMapper, но расширение или какое-либо архитектурное изменение, чтобы избежать этой инициализации, тоже сработало бы.
Я использую MVC 3, .NET 4 и не использую IoC / DI (по крайней мере, пока)
Комментарии:
1. Если у вас нет вызова конфигурации CreateMap, что должно произойти, когда что-то не отображается в Post -> PostModel map? То есть вы переименовали что-то в Post, но не переименовали это в PostModel?
Ответ №1:
Я совершенно неправильно понял, что вы пытались сделать в моем первоначальном ответе. Вы можете достичь желаемого, реализовав часть функциональности AutoMapper с использованием отражения. Это будет иметь очень ограниченную полезность, и чем больше вы расширяете его, тем больше он будет похож на AutoMapper, поэтому я не уверен, что в нем есть какая-либо долгосрочная ценность.
Я использую небольшую утилиту, подобную той, которую вы хотите автоматизировать в моей среде аудита, для копирования данных из модели сущности в связанную с ней модель аудита. Я создал его до того, как начал использовать AutoMapper, и не заменил его. Я называю это ReflectionHelper, приведенный ниже код является его модификацией (из памяти) — он обрабатывает только простые свойства, но при необходимости может быть адаптирован для поддержки вложенных моделей и коллекций. Это основано на соглашении, предполагающем, что свойства с одинаковым именем соответствуют и имеют одинаковый тип. Свойства, которые не существуют для копируемого типа, просто игнорируются.
public static class ReflectionHelper
{
public static T CreateFrom<T,U>( U from )
where T : class, new
where U : class
{
var to = Activator.CreateInstance<T>();
var toType = typeof(T);
var fromType = typeof(U);
foreach (var toProperty in toType.GetProperties())
{
var fromProperty = fromType.GetProperty( toProperty.Name );
if (fromProperty != null)
{
toProperty.SetValue( to, fromProperty.GetValue( from, null), null );
}
}
return to;
}
Используется как
var model = ReflectionHelper.CreateFrom<ViewModel,Model>( entity );
var entity = ReflectionHelper.CreateFrom<Model,ViewModel>( model );
Оригинал
Я выполняю свое отображение в статическом конструкторе. Mapper инициализируется при первом обращении к классу без необходимости вызова каких-либо методов. Однако я не делаю логический класс статическим, чтобы улучшить его тестируемость и тестируемость классов, использующих его в качестве зависимости.
public class BusinessLogicAutomapper
{
static BusinessLogicAutomapper
{
Mapper.CreateMap<Post, PostModel>();
Mapper.AssertConfigurationIsValid();
}
}
Ответ №2:
ознакомьтесь с профилями Automapper.
У меня есть эта настройка в моем Global.asax — она выполняется один раз статически, поэтому все настроено во время выполнения и готово к работе.
У меня также есть 1 модульный тест, который охватывает все карты, чтобы проверить их правильность.
Хорошим примером этого является блог Ayendes Raccoon