2017-04-22 259 views
1

我是AutoMapper的新手,试图映射ArrayItemLink[]使用AutoMapper映射类数组

public class ViewModel 
{ 
    public ItemLink[] ItemLinks { get; set; } 
} 

public class ItemLink 
{ 
    public string Description { get; set; } 
} 

我想:

Mapper.Map<viewModel.ItemLink>(db.ItemLinks); 

错误:

"Mapper not initialized. Call Initialize with appropriate configuration. If you are trying to use mapper instances through a container or otherwise, make sure you do not have any calls to the static Mapper.Map methods, and if you're using ProjectTo or UseAsDataSource extension methods, make sure you pass in the appropriate IConfigurationProvider instance."

不能把它简单映射?

编辑1

为了澄清更多的,我是从数据库中获取同等级结构。例如,

public class Db 
{ 
    public ItemLink[] ItemLinks { get; set; } 
} 

所以,我想与Db.ItemLink[]映射ViewModel.ItemLink[]

+0

您是否试图将数组映射到字符串?你能否重新设计这个问题? – Biswabid

+1

错误提示您在执行映射之前初始化配置。你可以按照[Automapper Wiki here](https://github.com/AutoMapper/AutoMapper/wiki/Configuration)的说明调用'AutoMapper.Mapper.Initialize()'来做到这一点,你必须确定你究竟是什么试图映射到什么。从你的代码看来,你似乎试图将一个'ItemLink []'映射到一个不是支持的映射的'ItemLink'。你想达到的究竟是什么? – granit

+0

@Biswabid:不,只是试图将db.ItemLink映射到viewmodel.ItemLink。 –

回答

3

地图,你不能提供变量为泛型p像你在Mapper.Map<viewModel.ItemLink>(db.ItemLinks);一样的参数。它被称为类型参数,并且必须是一个类型。

正如@gisek在他的回答中提到的,你需要首先配置mapper。通常它在应用程序启动时完成。

您可以考虑从数据库中获取完整的对象,但是您也可以选择使用Queryable Extensions,这些扩展仅用于获取视图模型所需的数据。

该配置。我假设你有用于数据库实体的命名空间DB,以及用于视图模型的View命名空间。

Mapper.Initialize(cfg => { 
    cfg.CreateMap<DB.ItemLink, View.ItemLink>(); 
}); 
Mapper.Configuration.AssertConfigurationIsValid(); 

从数据库获取全部的实体,然后将其映射到属性:从DB

var viewModel = new View.Item(); 
viewModel.ItemLinks = Mapper.Map<View.ItemLink[]>(db.ItemLinks.ToArray()); 

项目实体查看模式:

var viewModel = new View.Item(); 
viewModel.ItemLinks = db.ItemLinks.ProjectTo<View.ItemLink>().ToArray(); 
+0

@AshwiniVerma,你是否尝试过我在我的回答中发布的代码?对你起作用吗? –

+0

感谢Andrii的回答。对不起,延迟回复。它看起来不错,但我还没有测试它。我会很快确认 –

+1

谢谢,这工作完美。 –

0

您需要先配置映射器。

有两种可能的方法,静态和非静态。我倾向于非静态的,因为它允许您创建多个映射器,它们可以使用不同的映射策略。

非静态例如:

using AutoMapper; 

namespace Experiments 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var links = new ItemLink[] 
      { 
       new ItemLink {Description = "desc 1"}, 
       new ItemLink {Description = "desc 2"}, 
      }; 

      var item = new Item 
      { 
       ItemLinks = links, 
      }; 

      var config = new MapperConfiguration(cfg => 
      { 
       cfg.CreateMap<ItemLink, ItemLink>(); // you can extend this part of the configuration here 
       cfg.CreateMap<Item, Item>(); 
       cfg.CreateMap<ItemLink, MyCustomClass>() 
        .ForMember(myCustomClass => myCustomClass.DescriptionWithDifferentName, 
         expression => expression.MapFrom(itemLink => itemLink.Description)); // to map to a different type 
       // more configs can do here 
       // e.g. cfg.CreateMap<Item, SomeOtherClass>(); 
      }); 

      IMapper mapper = new Mapper(config); 
      ItemLink linkClone = mapper.Map<ItemLink>(links[0]); 
      ItemLink[] linkArrayClone = mapper.Map<ItemLink[]>(item.ItemLinks); 
      Item itemClone = mapper.Map<Item>(item); 
      MyCustomClass myCustomClassObject = mapper.Map<MyCustomClass>(links[0]); 
     } 
    } 

    public class Item 
    { 
     public ItemLink[] ItemLinks { get; set; } 
    } 

    public class ItemLink 
    { 
     public string Description { get; set; } 
    } 

    public class MyCustomClass 
    { 
     public string DescriptionWithDifferentName { get; set; } 
    } 
} 

静态例如:

using AutoMapper; 

namespace Experiments 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var links = new ItemLink[] 
      { 
       new ItemLink {Description = "desc 1"}, 
       new ItemLink {Description = "desc 2"}, 
      }; 

      var item = new Item 
      { 
       ItemLinks = links, 
      }; 

      Mapper.Initialize(cfg => 
      { 
       cfg.CreateMap<ItemLink, ItemLink>(); // you can extend this part of the configuration here 
       cfg.CreateMap<Item, Item>(); 
       cfg.CreateMap<ItemLink, MyCustomClass>() 
        .ForMember(myCustomClass => myCustomClass.DescriptionWithDifferentName, 
         expression => expression.MapFrom(itemLink => itemLink.Description)); 
        // to map to a different type 
       // more configs can do here 
       // e.g. cfg.CreateMap<Item, SomeOtherClass>(); 
      }); 

      ItemLink linkClone = Mapper.Map<ItemLink>(links[0]); 
      ItemLink[] linkArrayClone = Mapper.Map<ItemLink[]>(item.ItemLinks); 
      Item itemClone = Mapper.Map<Item>(item); 
      MyCustomClass myCustomClassObject = Mapper.Map<MyCustomClass>(links[0]); 
     } 

     public class Item 
     { 
      public ItemLink[] ItemLinks { get; set; } 
     } 

     public class ItemLink 
     { 
      public string Description { get; set; } 
     } 

     public class MyCustomClass 
     { 
      public string DescriptionWithDifferentName { get; set; } 
     } 
    } 
} 

您还可以配置Automapper创建失踪自动cfg.CreateMissingTypeMaps = true;

using AutoMapper; 

namespace Experiments 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var links = new ItemLink[] 
      { 
        new ItemLink {Description = "desc 1"}, 
        new ItemLink {Description = "desc 2"}, 
      }; 

      var item = new Item 
      { 
       ItemLinks = links, 
      }; 

      Mapper.Initialize(cfg => 
      { 
       // now AutoMapper will try co create maps on it's own 
       cfg.CreateMissingTypeMaps = true; 

       // we can still add custom maps like that 
       cfg.CreateMap<ItemLink, MyCustomClass>() 
        .ForMember(myCustomClass => myCustomClass.DescriptionWithDifferentName, 
         expression => expression.MapFrom(itemLink => itemLink.Description)); 
      }); 

      ItemLink linkClone = Mapper.Map<ItemLink>(links[0]); 
      ItemLink[] linkArrayClone = Mapper.Map<ItemLink[]>(item.ItemLinks); 
      Item itemClone = Mapper.Map<Item>(item); 

      // without custom map myCustomClassObject.DescriptionWithDifferentName would be null 
      MyCustomClass myCustomClassObject = Mapper.Map<MyCustomClass>(links[0]); 
     } 

     public class Item 
     { 
      public ItemLink[] ItemLinks { get; set; } 
     } 

     public class ItemLink 
     { 
      public string Description { get; set; } 
     } 

     public class MyCustomClass 
     { 
      public string DescriptionWithDifferentName { get; set; } 
     } 
    } 
} 
+0

感谢您的回答。 这一行说的是:cfg.CreateMap (); 和哪里是源数组(db.ItemLinks)? –

+0

@AshwiniVerma此行告诉Automapper“如何”将一个ItemLink类型的对象转换为另一个类型为ItemLink的对象。在这种情况下,我们说只是通过属性来克隆它。 Automapper设计要求我们提供一个配置,即使这个配置很微不足道。但是,更多的时候,我们需要更复杂的转换(请参阅更新的答案)。 – gisek

+0

@AshwiniVerma我还添加了一个片段,介绍静态方法 – gisek

2

我假设你正在使用.net mvc

首先你需要在应用程序启动时初始化你的映射,没有必要每次在你的控制器等初始化。

以下错误意味着你没有初始化映射器,automapper不知道你的源和目标对象。

错误:

"Mapper not initialized. Call Initialize with appropriate configuration. If you are trying to use mapper instances through a container or otherwise, make sure you do not have any calls to the static Mapper.Map methods, and if you're using ProjectTo or UseAsDataSource extension methods, make sure you pass in the appropriate IConfigurationProvider instance."

对于解决方案:

创建您的App_Start文件夹中的AutoMapperConfig对象。

public class AutoMapperConfig 
{ 
    public static void Register() 
    { 
     Mapper.Initialize(cfg => 
     { 
      cfg.CreateMap<source,destination>(); /*If source and destination object have same propery */ 
      cfg.CreateMap<source, destination>() 
      .ForMember(dest => dest.dId, opt => opt.MapFrom(src => src.sId)); /*If source and destination object haven't same property, you need do define which property refers to source property */ 
     }); 
    } 
} 

在你的Global.asax.cs

protected void Application_Start() 
    { 
     AreaRegistration.RegisterAllAreas(); 
     RouteConfig.RegisterRoutes(RouteTable.Routes); 
     BundleConfig.RegisterBundles(BundleTable.Bundles); 

     AutoMapperConfig.Register(); // Call Register method on App_Start 
    } 

In your controller

var mappedArray = Mapper.Map<viewmodel.ItemLink[]>(db.ItemLinks); 

var mappedArray = Mapper.Map<viewmodel.ItemLink[],ItemLinks[]>(db.ItemLinks); //ItemLinks[] refers to your dto. 
+0

为注册()提示投票。这会减少很多代码重复。 –

0

我不知道,我明白你需要什么, 我猜您正在尝试从一个ItemLink列表映射到al viewModel.ItemLink

的IST

所以Mapper.Map<viewModel.ItemLink>(db.ItemLinks);

成为

var listOfViewModelItemLink = Mapper.Map<List<viewModel.ItemLink>>(db.ItemLinks); 

您可以拨打listOfViewModelItemLink ToArray的(),然后分配给ItemLinks项目类的属性

+0

感谢您的答案,但这是行不通的。我已经试过了。 –

0

我不知道,但我猜您正试图从一个ItemLink数组映射到一个viewModel.ItemLink数组。你应该这样做:

var viewModels = db.ItemLinks 
     .ToArray() 
     .Select(x=>Mapper.Map<viewModel.ItemLink>(x)) 
     .ToArray();