如果已经在Automapper中创建了相同的地图,为什么我需要创建相同的地图?

时间:2016-11-12 21:02:28

标签: c# automapper

我正在使用Automapper 4.1.1,因为.NET Framework 4.0需要。我决定在每个应用程序启动时调用一次Automapper配置。所以,我的课程看起来像:

// AutoMapper Business Logic Layer Configuration

public class PersonProfile : Profile
{
    protected override void Configure()
    {
        Mapper.CreateMap<Person, PersonDTO>().ReverseMap();
    }
}

public class PhotoProfile : Profile
{
    protected override void Configure()
    {
        Mapper.CreateMap<Photo, PhotoDTO>().ReverseMap();
    }
}

public class DicProfile : Profile
{
    protected override void Configure()
    {
        Mapper.CreateMap<Dic, DicDTO>().ReverseMap();
    }
}

public class SubjectProfile : Profile
{
    protected override void Configure()
    {
        Mapper.CreateMap<Subject, SubjectDTO>().ReverseMap();
    }
}

public class PhotoSubjectIgnoreProfile : Profile
{
    protected override void Configure()
    {
        Mapper.CreateMap<Person, PersonDTO>()
              .ForMember(ph => ph.Photos, opt => opt.Ignore())
              .ForMember(sub => sub.Subjects, opt => opt.Ignore());
    }
}

public class PhotoSubjectIncludeProfile : Profile
{
    protected override void Configure()
    {
        Mapper.CreateMap<Person, PersonDTO>()
              .ForMember(pe => pe.Photos, opt => opt.MapFrom(p => p.Photos))
              .ForMember(dto => dto.Subjects, opt => opt.MapFrom(p => p.Subjects));
    }
}

// AutoMapper Presentation Layer Configuration

public class PersonViewProfile : Profile
{
    protected override void Configure()
    {
        Mapper.CreateMap<PersonDTO, PersonViewModel>()
              .ForMember(model => model.Photos, opt => opt.MapFrom(dto => dto.Photos))
              .ForMember(model => model.Subjects, opt => opt.MapFrom(dto => dto.Subjects))
              .ForMember(model => model.BirthdaySingle, opt => opt.MapFrom(dto => dto.BirthdaySingle.NullIntToNullDateTime("yyyyMMdd")));
        Mapper.CreateMap<PersonViewModel, PersonDTO>()
              .ForMember(dto => dto.Photos, opt => opt.MapFrom(model => model.Photos))
              .ForMember(dto => dto.Subjects, opt => opt.MapFrom(dto => dto.Subjects))
              .ForMember(dto => dto.BirthdaySingle, opt => opt.MapFrom(model => model.BirthdaySingle.NullDateTimeToNullInt("yyyyMMdd")));
    }
}

public class PersonShortViewProfile : Profile
{
    protected override void Configure()
    {
        Mapper.CreateMap<PersonDTO, PersonListViewModel.PersonShortViewModel>()
            .IgnoreAllNonExisting().ForMember(model => model.Birthday,opt => opt.MapFrom(dto => dto.BirthdaySingle.NullIntToNullDateTime("yyyyMMdd")));
    }
}
public class PhotoViewProfile : Profile
{
    protected override void Configure()
    {
        Mapper.CreateMap<PhotoDTO, PhotoViewModel>().ReverseMap();
    }
}

public class DicViewProfile:Profile
{
    protected override void Configure()
    {
        Mapper.CreateMap<DicDTO, DicViewModel>().ForSourceMember(dto => dto.Id, opt => opt.Ignore());
        Mapper.CreateMap<DicViewModel, DicDTO>().ForMember(dto => dto.Id, opt => opt.Ignore());
    }
}

public class SubjectViewProfile : Profile
{
    protected override void Configure()
    {
        Mapper.CreateMap<SubjectDTO, SubjectViewModel>().ForSourceMember(dto => dto.Id, opt => opt.Ignore());
        Mapper.CreateMap<SubjectViewModel, SubjectDTO>().ForMember(dto => dto.Id, opt => opt.Ignore());
    }
}

在整个应用程序中收集配置文件的类:

public static class AutoMapperConfiguration
{
    public static void Configure()
    {
        Mapper.Initialize(configuration =>
                          GetConfiguration(Mapper.Configuration)
            );
        Mapper.AssertConfigurationIsValid();
    }

    private static void GetConfiguration(IConfiguration configuration)
    {
        // Interesting thing: we need to use order by because we need photo mapping to be before Person mappings
        var assemblies = AppDomain.CurrentDomain.GetAssemblies();
        var allTypes = assemblies.SelectMany(assembly => assembly.GetExportedTypes());
        var profiles = allTypes.Where(type => typeof(Profile).IsAssignableFrom(type) && !type.IsAbstract && type.IsSubclassOf(typeof(Profile))).ToArray();

        foreach (var profile in profiles)
        {
            configuration.AddProfile(Activator.CreateInstance(profile) as Profile);
        }
    }
}

我在Program.cs类中调用main函数:

internal static class Program
{
    /// <summary>
    /// Главная точка входа для приложения.
    /// </summary>
    [STAThread]
    private static void Main()
    {
        AutoMapperConfiguration.Configure();
        // ...
    }
}

所以,我有一个方法:

/// <summary>
/// Get elements of type PersonDTO using paging settings
/// </summary>
/// <param name="pageNumber">Page number to get</param>
/// <param name="pageSize">Rows per page</param>
/// <returns></returns>
public IQueryable<PersonDTO> GetPersons(int pageNumber, int pageSize)
{
    if (pageNumber < 1)
    {
        throw new ValidationException("Початкове значення має бути більше 0.", "");
    }
    if (pageSize < 1)
    {
        throw new ValidationException("Кількість записів має бути більше 0.", "");
    }
    PageInfo.TotalItems = Database.Persons.CountAll();
    PageInfo.CurrentPage = pageNumber;
    PageInfo.PageSize = pageSize;

    // применяем автомаппер для проекции одной коллекции на другую
    /*Mapper.CreateMap<Person, PersonDTO>()
            .ForMember(ph => ph.Photos, opt => opt.Ignore())
            .ForMember(sub => sub.Subjects, opt => opt.Ignore());*/
    return Database.Persons.GetAll((pageNumber - 1) * pageSize, pageSize).ProjectTo<PersonDTO>();
}

我收到了这个错误:

Message:
Value cannot be null.
Parameter name: source

ParamName:
    source
Source:
    System.Core
StackTrace:
   at System.Linq.Enumerable.Select[TSource,TResult](IEnumerable`1 source, Func`2 selector)
   at lambda_method(Closure , Person )
   at System.Linq.Enumerable.<>c__DisplayClass7_0`3.<CombineSelectors>b__0(TSource x)
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at System.Windows.Forms.BindingSource.GetListFromEnumerable(IEnumerable enumerable)
   at System.Windows.Forms.BindingSource.ResetList()
   at System.Windows.Forms.BindingSource.set_DataSource(Object value)
   at Reestr.WinForms.Views.FrmMain.BindGrid(Int32 pageIndex, Expression`1 predicate) in B:\Programming\Visual Studio 2012\Projects\Reestr_2\Reestr.WinForms\Views\FrmMain.cs:line 270
TargetSite:
    {System.Collections.Generic.IEnumerable`1[TResult] Select[TSource,TResult](System.Collections.Generic.IEnumerable`1[TSource], System.Func`2[TSource,TResult])}
InnerException: null

但是!如果我取消注释Mapper.CreateMap行,则此错误消失,一切正常。无法理解为什么会这样,因为我已经在PhotoSubjectIgnoreProfile课程中创建了这个地图。 与方法相同的情况:

public PersonDTO GetPerson(long id)
{
    var person = Database.Persons.GetById(id);
    if (person == null)
    {
        throw new ValidationException("Об'єкт не знайдено.", "");
    }
    // применяем автомаппер для проекции Person на PersonDTO
    /*Mapper.CreateMap<Person, PersonDTO>()
        .ForMember(pe => pe.Photos, opt => opt.MapFrom(p => p.Photos))
        .ForMember(pe => pe.Subjects, opt => opt.MapFrom(p => p.Subjects));*/
    return Mapper.Map<PersonDTO>(person);
}

此地图也已在PhotoSubjectIncludeProfile课程中创建... 我怎么能解决这个问题?谢谢!

1 个答案:

答案 0 :(得分:1)

您的所有个人资料都不正确。您需要在个人资料上调用CreateMap,而不是Mapper.CreateMap:

public class PersonProfile : Profile
{
    protected override void Configure()
    {
        CreateMap<Person, PersonDTO>().ReverseMap();
    }
}