When using an ORM such as NHibernate or Entity Framework with AutoMapper's standard Mapper.Map functions, you may notice that the ORM will query all the fields of all the objects within a graph when AutoMapper is attempting to map the results to a destination type.

If your ORM exposes IQueryables, you can use AutoMapper's QueryableExtensions helper methods to address this key pain.

Using Entity Framework for an example, say that you have an entity OrderLine with a relationship with an entity Item. If you want to map this to an OrderLineDTO with the Item's Name property, the standard Mapper.Map call will result in Entity Framework querying the entire OrderLine and Item table.

Use this approach instead.

Given the following entities:

    public class OrderLine
{
public int Id { get; set; }
public int OrderId { get; set; }
public Item Item { get; set; }
public decimal Quantity { get; set; }
} public class Item
{
public int Id { get; set; }
public string Name { get; set; }
}
And the following DTO: public class OrderLineDTO
{
public int Id { get; set; }
public int OrderId { get; set; }
public string Item { get; set; }
public decimal Quantity { get; set; }
}
You can use the Queryable Extensions like so: Mapper.Initialize(cfg =>
cfg.CreateMap<OrderLine, OrderLineDTO>()
.ForMember(dto => dto.Item, conf => conf.MapFrom(ol => ol.Item.Name))); public List<OrderLineDTO> GetLinesForOrder(int orderId)
{
using (var context = new orderEntities())
{
return context.OrderLines.Where(ol => ol.OrderId == orderId)
.ProjectTo<OrderLineDTO>().ToList();
}
}
The .ProjectTo<OrderLineDTO>() will tell AutoMapper's mapping engine to emit a select clause to the IQueryable that will inform entity framework that it only needs to query the Name column of the Item table, same as if you manually projected your IQueryable to an OrderLineDTO with a Select clause. Note that for this feature to work, all type conversions must be explicitly handled in your Mapping. For example, you can not rely on the ToString() override of the Item class to inform entity framework to only select from the Name column, and any data type changes, such as Double to Decimal must be explicitly handled as well. Preventing lazy loading/SELECT N+ problems Because the LINQ projection built by AutoMapper is translated directly to a SQL query by the query provider, the mapping occurs at the SQL/ADO.NET level, and not touching your entities. All data is eagerly fetched and loaded into your DTOs. Nested collections use a Select to project child DTOs: from i in db.Instructors
orderby i.LastName
select new InstructorIndexData.InstructorModel
{
ID = i.ID,
FirstMidName = i.FirstMidName,
LastName = i.LastName,
HireDate = i.HireDate,
OfficeAssignmentLocation = i.OfficeAssignment.Location,
Courses = i.Courses.Select(c => new InstructorIndexData.InstructorCourseModel
{
CourseID = c.CourseID,
CourseTitle = c.Title
}).ToList()
};
This map through AutoMapper will result in a SELECT N+ problem, as each child Course will be queried one at a time, unless specified through your ORM to eagerly fetch. With LINQ projection, no special configuration or specification is needed with your ORM. The ORM uses the LINQ projection to build the exact SQL query needed. Custom projection In the case where members names don't line up, or you want to create calculated property, you can use MapFrom (and not ResolveUsing) to supply a custom expression for a destination member: Mapper.Initialize(cfg => cfg.CreateMap<Customer, CustomerDto>()
.ForMember(d => d.FullName, opt => opt.MapFrom(c => c.FirstName + " " + c.LastName))
.ForMember(d => d.TotalContacts, opt => opt.MapFrom(c => c.Contacts.Count()));
AutoMapper passes the supplied expression with the built projection. As long as your query provider can interpret the supplied expression, everything will be passed down all the way to the database. If the expression is rejected from your query provider (Entity Framework, NHibernate, etc.), you might need to tweak your expression until you find one that is accepted. Custom Type Conversion Occasionally, you need to completely replace a type conversion from a source to a destination type. In normal runtime mapping, this is accomplished via the ConvertUsing method. To perform the analog in LINQ projection, use the ProjectUsing method: cfg.CreateMap<Source, Dest>().ProjectUsing(src => new Dest { Value = });
ProjectUsing is slightly more limited than ConvertUsing as only what is allowed in an Expression and the underlying LINQ provider will work. Custom destination type constructors If your destination type has a custom constructor but you don't want to override the entire mapping, use the ConstructProjectionUsing method: cfg.CreateMap<Source, Dest>()
.ConstructProjectionUsing(src => new Dest(src.Value + ));
AutoMapper will automatically match up destination constructor parameters to source members based on matching names, so only use this method if AutoMapper can't match up the destination constructor properly, or if you need extra customization during construction. String conversion AutoMapper will automatically add ToString() when the destination member type is a string and the source member type is not. public class Order {
public OrderTypeEnum OrderType { get; set; }
}
public class OrderDto {
public string OrderType { get; set; }
}
var orders = dbContext.Orders.ProjectTo<OrderDto>().ToList();
orders[].OrderType.ShouldEqual("Online");
Explicit expansion In some scenarios, such as OData, a generic DTO is returned through an IQueryable controller action. Without explicit instructions, AutoMapper will expand all members in the result. To control which members are expanded during projection, pass in the members you want to explicitly expand: dbContext.Orders.ProjectTo<OrderDto>(
parameters = null,
dest => dest.Customer,
dest => dest.LineItems);
// or string-based
dbContext.Orders.ProjectTo<OrderDto>(
parameters = null,
"Customer",
"LineItems");
Aggregations LINQ can support aggregate queries, and AutoMapper supports LINQ extension methods. In the custom projection example, if we renamed the TotalContacts property to ContactsCount, AutoMapper would match to the Count() extension method and the LINQ provider would translate the count into a correlated subquery to aggregate child records. AutoMapper can also support complex aggregations and nested restrictions, if the LINQ provider supports it: cfg.CreateMap<Course, CourseModel>()
.ForMember(m => m.EnrollmentsStartingWithA,
opt => opt.MapFrom(c => c.Enrollments.Where(e => e.Student.LastName.StartsWith("A")).Count()));
This query returns the total number of students, for each course, whose last name starts with the letter 'A'. Parameterization Occasionally, projections need runtime parameters for their values. Consider a projection that needs to pull in the current username as part of its data. Instead of using post-mapping code, we can parameterize our MapFrom configuration: string currentUserName = null;
cfg.CreateMap<Course, CourseModel>()
.ForMember(m => m.CurrentUserName, opt => opt.MapFrom(src => currentUserName));
When we project, we'll substitute our parameter at runtime: dbContext.Courses.ProjectTo<CourseModel>(Config, new { currentUserName = Request.User.Name });
This works by capturing the name of the closure's field name in the original expression, then using an anonymous object/dictionary to apply the value to the parameter value before the query is sent to the query provider. Supported mapping options Not all mapping options can be supported, as the expression generated must be interpreted by a LINQ provider. Only what is supported by LINQ providers is supported by AutoMapper: MapFrom
Ignore
UseValue
NullSubstitute
Not supported: Condition
DoNotUseDestinationValue
SetMappingOrder
UseDestinationValue
ResolveUsing
Before/AfterMap
Custom resolvers
Custom type converters
Any calculated property on your domain object
Additionally, recursive or self-referencing destination types are not supported as LINQ providers do not support this. Typically hierarchical relational data models require common table expressions (CTEs) to correctly resolve a recursive join.

https://github.com/AutoMapper/AutoMapper/wiki/Queryable-Extensions

aufomaper Queryable Extensions ProjectTo的更多相关文章

  1. 16.AutoMapper 之可查询扩展(Queryable Extensions)

    https://www.jianshu.com/p/4b23e94a7825 可查询扩展(Queryable Extensions) 当在像NHibernate或者Entity Framework之类 ...

  2. AutoMapper queryable extensions 只找需要的字段

    http://jahav.com/blog/automapper-queryable-extensions/ How to generate a LINQ query for your DTOs Au ...

  3. AutoMapper 10.0使用教程

    这里有个目录 什么是AutoMapper 配置 使用MapperConfiguration配置 使用Profile Instances配置 Naming Conventions(命名约定) Repla ...

  4. 【AutoMapper官方文档】DTO与Domin Model相互转换(下)

    写在前面 AutoMapper目录: [AutoMapper官方文档]DTO与Domin Model相互转换(上) [AutoMapper官方文档]DTO与Domin Model相互转换(中) [Au ...

  5. Repository 仓储,你的归宿究竟在哪?(三)-SELECT 某某某。。。

    写在前面 首先,本篇博文主要包含两个主题: 领域服务中使用仓储 SELECT 某某某(有点晕?请看下面.) 上一篇:Repository 仓储,你的归宿究竟在哪?(二)-这样的应用层代码,你能接受吗? ...

  6. 【记录】AutoMapper Project To OrderBy Skip Take 正确写法

    AutoMapper:Queryable Extensions 示例代码: using (var context = new orderEntities()) { return context.Ord ...

  7. 【记录】AutoMapper Project To not support ResolveUsing

    示例代码: public List<OrderLineDTO> GetLinesForOrder(int orderId) { Mapper.CreateMap<OrderLine, ...

  8. AutoMapper 使用实践

    一.   使用意图 常常在开发过程中,碰到一个实体上的属性值,要赋值给另外一个相类似实体属性时,且属性有很多的情况.一般不利用工具的话,就要实例化被赋值实体B,然后再将实体A的字段一个个赋值给B的属性 ...

  9. DTO学习系列之AutoMapper(四)

    本篇目录: Mapping Inheritance-映射继承 Queryable Extensions (LINQ)-扩展查询表达式 Configuration-配置 Conditional Mapp ...

随机推荐

  1. C#元组示例详解

    元组的概要: 数组合并了相同类型的对象,而元组合并了不同类型的对象.元组起源于函数编程语言(如F#) ,在这些语言中频繁使用元组.在N盯4中,元组可通过.NET Fmmework用于所有的NET语言. ...

  2. javaweb写的在线聊天应用

    写这个玩意儿就是想练练手, 用户需要登陆才能在线聊天,不要依赖数据库, 不需要数据库的操作, 所有的数据都是保存在内存中, 如果服务器一旦重启,数据就没有了: 登录界面: 聊天界面: 左侧是在线的用户 ...

  3. 【HDU 4614】Vases and Flowers(线段树区间更新懒惰标记)

    题目0到n-1的花瓶,操作1在下标a开始插b朵花,输出始末下标.操作2清空[a,b]的花瓶,求清除的花的数量.线段树懒惰标记来更新区间.操作1,先查询0到a-1有num个空瓶子,然后用线段树的性质,或 ...

  4. iOS 蓝牙开发(四)BabyBluetooth蓝牙库介绍(转)

    转载自:http://www.cocoachina.com/ios/20151106/14072.html 原文作者:刘彦玮 BabyBluetooth 是一个最简单易用的蓝牙库,基于CoreBlue ...

  5. 【转】Timer还是Handler

    在我们Android开发过程中,经常需要执行一些短周期的定时任务,这时候有两个选择Timer或者Handler.然而个人认为:Handler在多个方面比Timer更为优秀,更推荐使用. 一.易用性 1 ...

  6. SQL Server 自增字段重置

    --- 删除原表数据,并重置自增列 truncate table tablename --truncate方式也可以重置自增字段 --重置表的自增字段,保留数据 DBCC CHECKIDENT (ta ...

  7. gene_abundance_estimation

    /home/liuhui/bin/trinityrnaseq_r20140413p1/util/support_scripts/get_Trinity_gene_to_trans_map.pl Tri ...

  8. Android Studio上面最好用的插件

    转载:http://www.jianshu.com/p/d76b60a3883d 在开发过程中,本人用的最爽的就是代码生成的插件,帮助我们自动完成大量重复简单的工作.个人也觉得代码自动生成工具是最值得 ...

  9. 【BZOJ-1042】硬币购物 容斥原理 + 完全背包

    1042: [HAOI2008]硬币购物 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1811  Solved: 1057[Submit][Stat ...

  10. win7、win8上SaveFileDialog窗口跳不出的问题

    xp上做的开一个线程 线程中数据以Excel形式保存到指定文件中的程序  放到win7 win8上都不跳出保存的对话框? 解决: 在win7.win8上都要对线程  在线程启动前设置其单元状态.设置为 ...