Вольный сокращенный перевод понравившегося поста с CodeProject. Рассматриваемые темы:
1. Projection
В отличие от автора, я бы поставил Configuration Validation на первое место по важности. Проверка соответствия свойств класса-результата и класса-источника гарантирует, что любые опечатки, переименования и просто несоответствия имен не останутся незамеченными. Маппинг становится прозрачным и предсказуемым. Но обо всем по порядку:
Допустим, в нашей БД есть таблица Doctor и соответствущая ей модель EF:
Иногда удобно вынести маппинг 2 сильно различающихся классов в отдельный класс:
DRY в действии, часто встречающиеся преобразования value-типов можно вынести в отдельный класс:
Подставляем значение по-умолчанию, если значение свойства-исходника равно null.
1. Projection
2. Configuration Validation
3. Custom Conversion
4. Value Resolvers
5. Null Substitution
В отличие от автора, я бы поставил Configuration Validation на первое место по важности. Проверка соответствия свойств класса-результата и класса-источника гарантирует, что любые опечатки, переименования и просто несоответствия имен не останутся незамеченными. Маппинг становится прозрачным и предсказуемым. Но обо всем по порядку:
1. Projection
Допустим, в нашей БД есть таблица Doctor и соответствущая ей модель EF:
public class Doctor
{
public int Id { get; set; }
public string Title { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
Предположим, нам не нужные полные данные данные из БД, а лишь достаточные для маппинга на поля следующего класса:
public class Person
{
public string Title { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
Следующий код:
public void DoctorProjectToPerson()
{
Mapper.CreateMap<Doctor, Person>()
.ForMember(dest => dest.LastName, opt => opt.Ignore());
using (MyContext context = new MyContext())
{
var person = context.Doctors
.Project().To<Person>().FirstOrDefault();
}
}
Приведет к SQL-запросу:
SELECT TOP (1)
[c].[Id] AS [Id],
[c].[FirstName] AS [FirstName]
FROM [dbo].[Doctors] AS [c]
Таким образом, из БД будут получены только поля, участвующие в маппинге <Doctor, Person>.2. Configuration Validation
//Mapper.CreateMap calls here...
Mapper.AssertConfigurationIsValid();
Тут все просто, метод AssertConfigurationIsValid сгенерирует исключение, если в любом классе-результате маппинга (destination) осталось хотя бы одно не замапленное public свойство.3. Custom Conversion
Иногда удобно вынести маппинг 2 сильно различающихся классов в отдельный класс:
Mapper.CreateMap<Doctor, HealthcareProfessional>()
.ConvertUsing<HealthcareProfessionalTypeConverter>();
public class HealthcareProfessionalTypeConverter
: ITypeConverter<Doctor, HealthcareProfessional>
{
public HealthcareProfessional Convert(ResolutionContext context)
{
if (context == null || context.IsSourceValueNull)
return null;
Doctor source = (Doctor)context.SourceValue;
return new HealthcareProfessional
{
FullName = string.Join(" ", new[]
{ source.Title, source.FirstName, source.LastName })
};
}
}
4. Value Resolvers
DRY в действии, часто встречающиеся преобразования value-типов можно вынести в отдельный класс:
Mapper.CreateMap<KitchenCutlery, Kitchen>()
.ForMember(dest => dest.KnifesAndForks,
opt => opt.ResolveUsing<KitchenResolver>());
public class KitchenResolver : ValueResolver<KitchenCutlery, int>
{
protected override int ResolveCore(KitchenCutlery source)
{
return source.Knifes + source.Forks;
}
}
5. Null Substitution
Подставляем значение по-умолчанию, если значение свойства-исходника равно null.
Mapper.CreateMap<Doctor, Person>()
.ForMember(dest => dest.Title, opt => opt.NullSubstitute("Dr"));
Комментариев нет:
Отправить комментарий