Есть ли общий способ использования ValueResolver AutoMapper для сопоставления значений EntityKey для объектов EF? - PullRequest
6 голосов
/ 27 января 2010

Не уверен, имеет ли название смысл, но вот что я делаю. Я использую AutoMapper для сопоставления моих Entity Framework Entities с моими объектами 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), но я считаю, что это довольно дорого и просто не правильно, хотя, это работает.

1 Ответ

8 голосов
/ 28 января 2010

Я не зашел так далеко, чтобы проверить это, но должно работать следующее:

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)));

Что касается вашего другого вопроса, у меня появилась привычка создавать статический класс, который инициализирует мои карты и устанавливает логическое значение относительно того, созданы ли сопоставления, так как вам нужно вызывать его только один раз для AppDomain. Затем в конструкторе моего хранилища я просто вызываю MapInitializer.EnsureMaps();

...