Не уверенный, если заголовок имеет смысл, но здесь - то, что я делаю. Я использую AutoMapper для отображения моих Объектов Платформы Объекта на мои объекты DTO и наоборот. Проблема прибывает, когда я пытаюсь отобразить данные DTO на объект EF. Нет свойства к свойству, отображающемуся для EntityKey. Для фиксации этого я делаю некоторым нравится следующее:
Mapper.CreateMap<VideoDTO, Video>()
.ForMember(dest => dest.EntityKey, opt =>
opt.ResolveUsing<VideoEntityKeyResolver>());
Класс VideoEntityKeyResolver похож:
public class VideoEntityKeyResolver : ValueResolver<VideoDTO, EntityKey>
{
protected override EntityKey ResolveCore(VideoDTO source)
{
EntityKey key = new EntityKey("EntityFrameworkTestingEntities.Videos",
"VideoId", source.VideoId);
return key;
}
}
Я задавался вопросом, был ли более универсальный способ сделать это, где у меня мог быть 1 класс с конструктором, который берет Имя Множества сущностей, Ключевое Имя Свойства и Значение ключа в конструкторе.
Я думал о просто добавлении свойства EntityKey к моим объектам DTO, которое много походит на пересечение потоков, поскольку смыслом создания объектов DTO была к серьезному связь с моим слоем данных в остальной части моего приложения.
На абсолютно несвязанной ноте (я могу создать новый вопрос в случае необходимости), где точно я должен определить свои отображения при использовании AutoMapper? В настоящее время я делаю его в конструкторе моего объекта контекста (который является моим объектом репозитария EF), но я полагаю, что это является довольно дорогостоящим и просто не корректным, тем не менее, это работает.
Я не заходил так далеко, чтобы тестировать это, но следующее должно работать:
public class EntityKeyResolver<T, TProperty> : ValueResolver<T, EntityKey> where T : class
{
private Expression<Func<T, TProperty>> _propertyExpression;
private string _qualifiedEntitySetName;
private string _keyName;
public EntityKeyResolver(string qualifiedEntitySetName, string keyName, Expression<Func<T, TProperty>> propertyExpression)
{
_qualifiedEntitySetName = qualifiedEntitySetName;
_keyName = keyName;
_propertyExpression = propertyExpression;
}
protected override EntityKey ResolveCore(T source)
{
return new EntityKey(_qualifiedEntitySetName, _keyName, ExpressionHelper.GetValue(_propertyExpression));
}
}
ExpressionHelper
является статическим класс, который я использую для оценки выражений в различных случаях. Метод GetValue выглядит следующим образом:
internal static TProperty GetValue<T, TProperty>(T obj, Expression<Func<T, TProperty>> expression) where T : class
{
if (obj == null)
{
return default(TProperty);
}
Func<T, TProperty> func = expression.Compile();
return func(obj);
}
Затем вы должны изменить свой код следующим образом (при условии, что VideoId - это Guid):
Mapper.CreateMap<VideoDTO, Video>()
.ForMember(dest => dest.EntityKey, opt => opt.ResolveUsing(new EntityKeyResolver<VideoDTO, Guid>("EntityFrameworkTestingEntities.Videos", "VideoId", v => v.VideoId)));
Возможно, более подробный, чем вы хотели. Альтернативой универсальному преобразователю могло бы быть использование MapFrom для сопоставления ключа объекта (они примерно одинаково подробны):
Mapper.CreateMap<VideoDTO, Video>()
.ForMember(dest => dest.EntityKey, opt => opt.MapFrom(src => new EntityKey("EntityFrameworkTestingEntities.Videos", "VideoId", src.VideoId)));
Что касается вашего другого вопроса, у меня появилась привычка создавать статический класс, который инициализирует мои карты и устанавливает логическое значение, указывающее, были ли созданы сопоставления, поскольку вам нужно вызвать его только один раз для каждого домена приложения. Затем в конструкторе своего репозитория я просто вызываю MapInitializer.EnsureMaps ();