When EntityFramework fell in love with AutoMapper

Source: Internet
Author: User

Sometimes acquaintance is a kind of fate, love does not need too many reasons, a look enough, when EntityFramework met AutoMapper, is so, love is easy, get along easily.

In DDD (domain driven design), using the AutoMapper general scenario is the transformation of the data object between the domain layer and the presentation layer (the presentation layer), which is the conversion between the DTO and the Domin model, But if you have an in-depth understanding of automapper, you will find that the areas in which she is involved are not confined to this, but should include conversions between all objects. On the other side, when EntityFramework still in for single distress, casual moment acquaintance AutoMapper, henceforth deeply fell in love with her.

AutoMapper is a powerful object-object mapping tool, for AutoMapper please refer to:

    • "AutoMapper Official Document" DTO and Domin model Mutual conversion (UP)
    • "AutoMapper Official Document" DTO and Domin Model conversion (middle)
    • "AutoMapper Official Document" DTO and Domin model mutual conversion (bottom)
Why Love?

Above is the AutoMapper object conversion, you can see that the main purpose of AutoMapper is used in the object mapping transformation, she no matter what object, just responsible for conversion, just like a woman at home is responsible for the same as the child. Look at the basic usage of AutoMapper:

1       //configuration AutoMapper2       Mapper.createmap<order, orderdto> (); 3       //execute Mapping4       orderdto dto = Mapper.map<order, orderdto> (Order);

What is EntityFramework? He is a Microsoft-developed Object/relational Mapping framework, a big man, a man of identity and status, like a "Prince", and AutoMapper exactly a small role, just like "Cinderella" Besides, they are not the people of the world, so why would entityframework fancy automapper? There must be something inside, and we'll explore.

If there is a business scenario where there is millions order data in the order table, and the order table has hundreds of columns, according to the business scenario, we need to separate the orders, such as customer information orders, product orders, and so on, which may only be used in certain fields in the order table, if we do such an operation, You can imagine how the data is queried, some fields we don't need are queried, and the data is not filtered, so let's do one of these things at the data Access layer:

 1 using (var context = new OrderContext ()) 2 {3 var Orderconsignee = from order in CONTEXT.O                                      Rders 4 Select New Orderconsignee 5 {6 Orderconsigneeid = order. OrderId, 7//orderitems = order. OrderItems, 8 Orderitemcount = order. Orderitemcount, 9 consigneename = order. consigneename,10 consigneerealname = order. consigneerealname,11 Consigneephone = order. consigneephone,12 consigneeprovince = order. consigneeprovince,13 consigneeaddress = order. consigneeaddress,14 Consigneezip = order. consigneezip,15 Consigneetel = order. Consigneetel,Consigneefax = order. consigneefax,17 Consigneeemail = order. CONSIGNEEEMAIL18};
Console.readkey (); 20}

Orderconsignee represents the order customer, which is just a subset of the separation of order information, if there are many separate subsets, and the fields in the subset are not much less than the order table, you will find how much effort is required to populate those subsets in the data access layer, although it is efficient, As you can see from the generated SQL code:

1 SELECT  2     [extent1].[ Orderitemcount] As [Orderitemcount],  3     [extent1].[ OrderId] As [OrderId],  4     [extent1].[ Consigneename] As [Consigneename],  5     [extent1].[ Consigneerealname] As [Consigneerealname],  6     [extent1].[ Consigneephone] As [Consigneephone],  7     [extent1].[ Consigneeprovince] As [consigneeprovince],  8     [extent1].[ Consigneeaddress] As [consigneeaddress],  9     [extent1].[ Consigneezip] As [Consigneezip], ten     [extent1].[ Consigneetel] As [Consigneetel], one     [extent1].[ Consigneefax] As [Consigneefax],     [extent1].[ Consigneeemail] As [consigneeemail]13 from     [dbo].[ Orders] as [Extent1]

But this effect does not make entityframework satisfied, so he stared at someone else automapper, why? Because AutoMapper a piece of code can solve the above problem:

1     orderdto dto = Mapper.map<order, orderdto> (Order);
The problem of getting along?

Because EntityFramework's crazy pursuit, coupled with his eminent status, let AutoMapper have to accept him, so they went out, but it seems to be Hou Yi Goddess story, not a world people, get along with some problems always arise. Although AutoMapper is powerful in object conversions, and most scenarios are mapping transformations between domain and ViewModel, automapper is not so useful when it comes to data access. In other words, AutoMapper works in-memory object conversion, not application IQueryable interface in data access, and at the data access layer we use EntityFramework to convert the object being queried into a SQL command, If you use AutoMapper at the data Access layer, the query data must occur after the mapping transformation, and the data you query must be more than the converted data, resulting in performance problems.

In the example above we modify the following:

1     Mapper.createmap<order, orderconsignee> (); 2     var details = Mapper.map<ienumerable<order> Ienumerable<orderconsignee>> (context. Orders). ToList ();

In fact, this is the reason EntityFramework see AutoMapper, but also entityframework want the effect, look at the generated SQL statement:

 1 SELECT 2 [Extent1]. [OrderId] As [OrderId], 3 [Extent1]. [Orderitemcount] As [Orderitemcount], 4 [Extent1]. [UserId] As [UserId], 5 [Extent1]. [Receiverid] As [Receiverid], 6 [Extent1]. [Shopdate] As [Shopdate], 7 [Extent1]. [OrderDate] As [OrderDate], 8 [Extent1]. [Consigneerealname] As [Consigneerealname], 9 [Extent1]. [Consigneename] As [consigneename],10 [Extent1]. [Consigneephone] As [consigneephone],11 [Extent1]. [Consigneeprovince] As [consigneeprovince],12 [Extent1]. [Consigneeaddress] As [consigneeaddress],13 [Extent1]. [Consigneezip] As [consigneezip],14 [Extent1]. [Consigneetel] As [consigneetel],15 [Extent1]. [Consigneefax] As [consigneefax],16 [Extent1]. [Consigneeemail] As [consigneeemail],17 [Extent1]. [Whethercouandinte] As [whethercouandinte],18 [Extent1]. [Parvalueandinte] As [parvalueandinte],19 [Extent1]. [Paymenttype] As [paymenttype],20 [Extent1]. [Payment] As [payment],21 [Extent1]. [Courier] As [Courier],22 [Extent1]. [Totalprice] As [totalprice],23 [Extent1]. [Factprice] As [factprice],24 [Extent1]. [Invoice] As [invoice],25 [Extent1]. [Remark] As [remark],26 [Extent1]. [Orderstatus] As [orderstatus],27 [Extent1]. [Saleuserid] As [saleuserid],28 [Extent1]. [Saleusertype] As [saleusertype],29 [Extent1]. [Businessmanid] As [businessmanid],30 [Extent1]. [Carriage] As [carriage],31 [Extent1]. [Paymentstatus] As [paymentstatus],32 [Extent1]. [Ogisticsstatus] As [ogisticsstatus],33 [Extent1]. [OrderType] As [ordertype],34 [Extent1]. [Isordernormal] As [isordernormal]35 from [dbo]. [Orders] As [Extent1]

Through the SQL statement above, it will be found that although the data Access layer code is simple to write, but the query field is not what we want, that is, the query occurs before the mapping, you can imagine if there are millions of data or hundreds of rows, using automapper mapping conversion is how unreliable, Don't entityframework and AutoMapper have no fate? Or is it just EntityFramework's wishful thinking? Please look below.

The greatness of a woman?

In the process of entityframework and automapper, although there are some problems, but in fact, it is not entityframework fault, wrong in their life is not on the ground, By getting along AutoMapper also found that entityframework is really good for her, so AutoMapper decided to make some changes, in order to EntityFramework, but also for their future.

EntityFramework and AutoMapper not a world of reasons, we also analyzed before, one exists in memory, one exists in the data access, AutoMapper to do is to expand the IQueryable expression (a bit of the meaning of the Chang ' an), So that they can exist in a world, so she did the following work for EntityFramework:

 1 public static class Queryableextensions 2 {3 public static projectionexpression<tsource> Project <TSource> (this iqueryable<tsource> source) 4 {5 return new PROJECTIONEXPRESSION&LT;TSOURC E> (source); 6} 7} 8 9 public class Projectionexpression<tsource>10 {One private static readonly Di ctionary<string, expression> expressioncache = new dictionary<string, expression> (); private read         Only iqueryable<tsource> _source;14 projectionexpression (iqueryable<tsource> source) 16 {_source = source;18}19 public iqueryable<tdest> to<tdest> () 21 { var queryexpression = getcachedexpression<tdest> ()?? Buildexpression<tdest> (); _source return. Select (QueryExpression), and the private static Expression<func<tsource, tdest>> getcachedexpression<tdest> () {var key = getcachekey<tdest> (); Eturn Expressioncache.containskey (key)? Expressioncache[key] as Expression<func<tsource, tdest>>: null;32}33 private static Expre Ssion<func<tsource, tdest>> buildexpression<tdest> () {var sourceproperties = Ty Peof (TSource). GetProperties (); PNS var destinationproperties = typeof (Tdest). GetProperties (). Where (dest = dest.             CanWrite); var parameterexpression = Expression.parameter (typeof (TSource), "Src"); 39 40 var bindings = destinationProperties41.                                 Select (Destinationproperty = buildbinding (ParameterExpression, Destinationproperty, sourceproperties)) 42 . Where (binding = binding = NULL); expression.lambda<func<tsource var expression = Tdest>&gt ;(ExprEssion. Memberinit (Expression.new (typeof (Tdest)), bindings), parameterexpression), var key = Getcachekey<tdest > (); Expressioncache.add (key, expression); expression;51} 52 5 3 private static Memberassignment buildbinding (Expression parameterexpression, MemberInfo Destinationproperty, IEn Umerable<propertyinfo> sourceproperties) {var sourceproperty = Sourceproperties.firstordefa Ult (src = src. Name = = destinationproperty.name); sourceproperty = (null) Xpression. Bind (Destinationproperty, Expression.property (ParameterExpression, Sourceproperty)),}61 var PropertyNames = Splitcamelcase (Destinationproperty.name), if (propertynames.length = = 2) 65 {6 6 sourceproperty = sourceproperties.firstordefault (src = src. Name = = Propertynames[0]); 67 68 if (sourceproperty! = null) Sourcechildproperty {$ var = sourcepr Operty. Propertytype.getproperties (). FirstOrDefault (src = src.                         Name = = Propertynames[1]); if (sourcechildproperty! = null) 73 {74 Return Expression.bind (Destinationproperty, Expression.property (Expression.property (parameterexpression, Sour Ceproperty) (Sourcechildproperty));}76}77}78 return nu Ll;80}81-getcachekey<tdest> (). Concat (typeof (TSource). FullName, typeof (Tdest). FullName);}86 (string[) splitcamelcase (string input) Regex.Replace (Input, "([A-z])", "$", regexoptions.compiled). Trim ().     Split ('); 90}91}

To modify the sample code:

1       Mapper.createmap<order, orderconsignee> (); 2       var details = context. Orders.project (). To<orderconsignee> ();

The effort made by AutoMapper makes the code much simpler, as long as you configure a type mapping, pass the target type, and get the transformation object that we want, the code is so concise, and then we look at the SQL code that is generated:

 1 SELECT 2 [Project1]. [OrderId] As [OrderId], 3 [Project1]. [Orderitemcount] As [Orderitemcount], 4 [Project1]. [Consigneerealname] As [Consigneerealname], 5 [Project1]. [Consigneename] As [Consigneename], 6 [Project1]. [Consigneephone] As [Consigneephone], 7 [Project1]. [Consigneeprovince] As [consigneeprovince], 8 [Project1]. [Consigneeaddress] As [consigneeaddress], 9 [Project1]. [Consigneezip] As [Consigneezip], [Project1]. [Consigneetel] As [Consigneetel], one by one [Project1]. [Consigneefax] As [Consigneefax], [Project1]. [Consigneeemail] As [Consigneeemail], [Project1]. [C1] As [C1], [Project1]. [Orderitemid] As [Orderitemid], [Project1]. [Proname] As [Proname], [Project1]. [Proimg] As [proimg], [Project1]. [Proprice] As [Proprice], [Project1]. [Pronum] As [Pronum], [Project1]. [Addtime] As [Addtime], [Project1]. [Prootherpara] As [Prootherpara], [Project1]. [Order_orderid] As [Order_Orderid]22 from (SELECT [extent1].[ OrderId] As [OrderId], [Extent1]. [Orderitemcount] As [Orderitemcount], [Extent1]. [Consigneerealname] As [Consigneerealname], [Extent1]. [Consigneename] As [Consigneename], [Extent1]. [Consigneephone] As [Consigneephone], [Extent1]. [Consigneeprovince] As [Consigneeprovince], [Extent1]. [Consigneeaddress] As [consigneeaddress], [Extent1]. [Consigneezip] As [Consigneezip], [Extent1]. [Consigneetel] As [Consigneetel], [Extent1]. [Consigneefax] As [Consigneefax], [Extent1]. [Consigneeemail] As [Consigneeemail], [Extent2]. [Orderitemid] As [Orderitemid], [Extent2]. [Proname] As [Proname], [Extent2]. [Proimg] As [proimg], Panax Notoginseng [Extent2]. [Proprice] As [Proprice], [Extent2]. [Pronum] As [Pronum], [Extent2]. [Addtime] As [Addtime], [Extent2]. [Prootherpara] As [Prootherpara], 41        [Extent2]. [Order_orderid] As [Order_orderid], when ([extent2].[ Orderitemid] is NULL) then CAST (NULL as int) ELSE 1 END as [c1]43 from [dbo]. [Orders] As [extent1]44 left OUTER JOIN [dbo]. [OrderItems] As [Extent2] on [Extent1]. [OrderId] = [Extent2]. [order_orderid]45] as [project1]46 Order by [Project1]. [OrderId] ASC, [Project1]. [C1] Asc

As you can see, because order and Orderconsignee contain mappings to a subset of OrderItems:

1//<SUMMARY>2///         Order Item 3//         </summary>4 public         virtual icollection<orderitem> OrderItems {get; set;}

So AutoMapper will automatically match the associated subset to query, of course, you can also create a mapping relationship when the OrderItems is ignored: Mapper.createmap<order, orderconsignee> (). Formember (dest = dest. OrderItems, opt = opt. Ignore ()); Exclude OrderItems related factors, from the SQL code can be seen and do not query the extra fields, that is, we want the effect, this is all attributed to AutoMapper, perhaps if there is no automapper effort, She and EntityFramework can not really be together, woman is really great ah.

The end of the story?

Sample code Download: Http://pan.baidu.com/s/1c0h9TNM

After all the ups and downs, EntityFramework finally and AutoMapper had a happy day, but seemingly happy, but the problem is still constant, some people ask questions:

    • http://rogeralsing.com/2013/12/01/why-mapping-dtos-to-entities-using-automapper-and-entityframework-is-horrible/

The title of the article used the word "horrible", translated as scary, is it said that EntityFramework and automapper are so horrible together? Of course this is only for entityframework use AutoMapper for curd operation, but I believe EntityFramework and AutoMapper will overcome many difficulties, life and death. And we'll keep an eye on their married life.

When EntityFramework fell in love with AutoMapper

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.