AutoMapper เทียบกับ ValueInjecter [ปิด]


209

ทุกครั้งที่ผมกำลังมองหาAutoMapperสิ่งใน StackOverflow ผมอ่านบางอย่างเกี่ยวกับValueInjecter

ใครสามารถบอกข้อดีข้อเสียระหว่างพวกเขา (ประสิทธิภาพคุณลักษณะการใช้งาน API ความสามารถในการขยายการทดสอบ)


2
หนึ่งที่ผมเห็นที่กล่าวถึงมากอีกประการหนึ่งคือEmitMapper
adrianbanks

1
แล้วกาวล่ะ glue.codeplex.comดูเหมือนว่าจะเป็นโครงการที่ยอดเยี่ยมเช่นกัน แต่ฉันยังไม่ได้ลองเลย ฉันจะทำในเดือนหน้า ฉันเคยเห็นโครงการที่เรียกว่า EmitMapper emitmapper.codeplex.com
Trygve

ดูบทความที่พูดถึงเครื่องมือทั้งสองนี้ - devproconnections.com/development/ …
George Birbilis

คำตอบ:


170

ในฐานะผู้สร้างValueInjecterฉันสามารถบอกคุณได้ว่าฉันทำเพราะฉันต้องการบางสิ่งที่ง่ายและยืดหยุ่นมาก

ฉันไม่ชอบเขียนมากหรือเขียนอะไรมากมายmonkey code:

Prop1.Ignore, Prop2.Ignore etc.
CreateMap<Foo,Bar>(); CreateMap<Tomato, Potato>(); etc.

ValueInjecter เป็นบางสิ่งบางอย่างเช่น mozilla พร้อมด้วยปลั๊กอินคุณสร้าง ValueInjections และใช้มัน

มีการฉีดในตัวสำหรับการทำให้แบนราบไม่ทำให้แบนราบและบางอันมีไว้เพื่อสืบทอด

และใช้งานได้มากกว่าในลักษณะที่เป็นลักษณะคุณไม่ต้องระบุคุณสมบัติทั้งหมด 1 ต่อ 1 แทนคุณทำสิ่งที่ชอบ:

ใช้คุณสมบัติ int ทั้งหมดจากแหล่งที่ชื่อลงท้ายด้วย "Id" เปลี่ยนค่าและตั้งค่าให้กับคุณสมบัติในวัตถุต้นฉบับที่มีชื่อเดียวกันโดยไม่มีส่วนต่อท้าย Id และประเภทนั้นสืบทอดมาจาก Entity เช่นนั้น

ดังนั้นความแตกต่างที่เห็นได้ชัดอย่างหนึ่ง ValueInjecter ถูกนำมาใช้แม้ในรูปแบบ windows ที่มีความแบนและไม่แบนนั่นคือความยืดหยุ่น

(การแมปจากวัตถุเพื่อควบคุมฟอร์มและย้อนกลับ)

Automapper, ไม่สามารถใช้งานได้ในรูปแบบ windows, ไม่มีการยกเลิกการเผยแพร่ แต่มันมีสิ่งที่ดีเช่นการจับคู่คอลเลกชันดังนั้นในกรณีที่คุณต้องการด้วย ValueInjecter คุณเพียงแค่ทำสิ่งต่อไปนี้:

foos.Select(o => new Bar().InjectFrom(o));

คุณยังสามารถใช้ ValueInjecter เพื่อแมปจากวัตถุที่ไม่ระบุชื่อและไดนามิก

ความแตกต่าง:

  • automapper สร้างการกำหนดค่าสำหรับความเป็นไปได้ในการทำแผนที่แต่ละครั้ง CreateMap ()

  • valueinjecter ฉีดจากวัตถุใด ๆ ไปยังวัตถุใด ๆ (นอกจากนี้ยังมีบางกรณีเมื่อคุณฉีดจากวัตถุไปยังประเภทที่มีค่า)

  • automapper มีตัวแบนมันและสำหรับประเภทที่เรียบง่ายหรือจากประเภทเดียวกันและมันก็ไม่ได้ทำให้ราบ

  • valueinjecter เท่านั้นถ้าคุณต้องการที่คุณทำtarget.InjectFrom<FlatLoopValueInjection>(source); also <UnflatLoopValueInjection> และถ้าคุณต้องการจากFoo.Bar.Name of type StringการFooBarName of type Class1ที่คุณได้รับมรดก FlatLoopValueInjection และระบุนี้

  • automapper แผนที่คุณสมบัติที่มีชื่อเดียวกันโดยค่าเริ่มต้นและสำหรับส่วนที่เหลือคุณต้องระบุทีละคนและทำสิ่งต่าง ๆ เช่น Prop1.Ignore (), Prop2.Ignore () ฯลฯ

  • valueinjecter มีการเริ่มต้นการฉีด. InjectFrom () ที่ทำคุณสมบัติที่มีชื่อและประเภทเดียวกัน สำหรับทุกสิ่งทุกอย่างที่คุณสร้างมูลค่าที่กำหนดเองของคุณด้วยตรรกะการทำแผนที่ / กฎการทำแผนที่แต่ละอย่างเช่นด้านอื่น ๆ เช่นจากอุปกรณ์ประกอบฉากทุกประเภทของ Foo ไปจนถึงอุปกรณ์ประกอบฉากทั้งหมดของบาร์


5
สำหรับพระเจ้าแห่งความรักโปรดบอกฉัน ValueInjector สามารถใช้กราฟ ViewModel แบบลึกและแผนที่ไปยัง / จาก Business Entity ของกราฟแบบลึกและแผนที่ทุกอย่างที่เหมือนกันโดยไม่ต้องทำงานและฉันต้องระบุวิธีจัดการกับสิ่งที่แตกต่างกัน ฉันหวังว่า AutoMapper จะเพิ่มความสามารถนี้ แต่มันไม่เคยเกิดขึ้นจริงและฉันไม่มีเวลาเขียนตัวทำแผนที่อัตโนมัติของฉันเอง
Chris Marisic

3
@Chris Marisic คุณสามารถใช้มันได้ในกรณีที่คุณหมายถึงการโคลนนิ่งลึกฉันได้ทำการฉีดครั้งเดียวเมื่อมันทำแบบนี้ซ้ำแล้วซ้ำอีก แต่ไม่ได้ผลกับคอลเลกชันคุณสมบัติvalueinjecter.codeplex.com/Thread/View.aspx?ThreadId=236126หรือคุณสามารถทำแบน ViewModel และใช้แฟบและ unflattening นี้จะง่าย
Omu

ViewModel และหน่วยงานโดเมนจะคล้ายกัน แต่แตกต่างกันดังนั้นจึงไม่เป็นโคลนที่แท้จริง 90% ของคุณสมบัติมักจะเป็นประเภทและชื่อที่แน่นอน ViewModels มักจะจบลงด้วย SelectLists และสิ่งต่าง ๆ ที่ผูกไว้กับสิ่งที่พวกเขาต้องการที่จะไม่สนใจกลับมาที่โดเมน ทั้งสองมีแนวโน้มที่จะมีชุดของวัตถุที่พวกเขาว่า
Chris Marisic

27
<pedant>ดูดี แต่บางทีมันควรจะเป็น ValueInject หรือ </pedant>
Craig Stuntz

1
แต่ด้วยเหตุผลบางอย่างก็เอ้อ :)
Omu

59

เนื่องจากฉันไม่เคยใช้เครื่องมืออื่น ๆ เลยฉันสามารถพูดคุยเกี่ยวกับ AutoMapper ได้เท่านั้น ฉันมีเป้าหมายสองสามข้อในการสร้าง AutoMapper:

  • สนับสนุนการแบนให้วัตถุ DTO เป็นใบ้
  • รองรับสถานการณ์ที่ชัดเจนนอกกรอบ (คอลเลกชันการแจกแจง ฯลฯ )
  • สามารถตรวจสอบการแมปได้ง่าย ๆ ในการทดสอบ
  • อนุญาตให้เคสขอบสำหรับการแก้ไขค่าจากที่อื่น (การแม็พชนิด -> ชนิดที่กำหนดเอง, การแม็พสมาชิกแต่ละราย, และเคสขอบบ้าจริง ๆ )

หากคุณต้องการทำสิ่งเหล่านี้ AutoMapper ทำงานได้ดีสำหรับคุณ สิ่งที่ AutoMapper ทำได้ไม่ดีคือ:

  • การเติมวัตถุที่มีอยู่
  • Unflattening

เหตุผลที่ฉันไม่จำเป็นต้องทำสิ่งเหล่านี้ ส่วนใหญ่หน่วยงานของเราไม่มีเซ็ตเตอร์อย่าเปิดเผยคอลเลกชัน ฯลฯ นั่นคือสาเหตุที่มันไม่มี เราใช้ AutoMapper เพื่อทำให้แบนไปที่ DTO และแมปจากโมเดล UI ไปยังข้อความคำสั่งและสิ่งที่ชอบ นั่นคือสิ่งที่มันใช้งานได้ดีจริงๆสำหรับเรา


1
@Jimmy Bogard คุณเห็นไหมว่าการเติมวัตถุที่มีอยู่จะทำให้มันกลายเป็นรายการคุณสมบัติสำหรับ AutoMapper หรือไม่?
โรมัน

ฉันไม่ได้ลอง ValueInjecter แต่สำหรับสิ่งที่เราต้องการ automapper มีประสิทธิภาพมาก
richb01

ฉันคิดว่าสิ่งที่สำคัญที่สุดที่นี่คือการตรวจสอบได้ เมื่อทำการเปลี่ยนชื่อและสร้างสิ่งใหม่สิ่งนี้เป็นความช่วยเหลือที่ยิ่งใหญ่
Kugel

55

ฉันลองทั้งสองและชอบ ValueInjecter เพราะมันง่ายมาก:

myObject.InjectFrom(otherObject);

นั่นคือทั้งหมดที่ต้องรู้สำหรับความต้องการฉีดส่วนใหญ่ของฉัน มันไม่อาจเรียบง่ายและดูดีไปกว่านี้อีกแล้ว


1
this objectวิธีการขยายมี?
Chris Marisic

2
ฉันจะแยกรหัสออกจาก ValueInjecter ได้อย่างไร สำหรับฉันดูเหมือนว่าจะมีการพึ่งพา ValueInjecter เช่นในโครงการเว็บของฉันเพราะฉันใช้ ValueInjecter (วิธีการขยาย) บนวัตถุที่กำหนดโดยตรง
Rookian

1
@Rookian โดยสุจริตนี่ไม่ใช่ข้อกังวลที่คุณควรคิดมากเกินไป คุณสามารถพึ่งพาอินเทอร์เฟซอย่างที่ @Omu พูดถึงดังนั้นหากคุณเคยเปลี่ยน mappers คุณอาจบันทึกงานบางอย่าง (อาจไม่มาก) การพึ่งพาประเภทนี้ยากเกินกว่าที่จะสรุปออกไปได้เว้นแต่ว่าคุณต้องการเข้าสู่ AOP แบบเต็มซึ่งน่าเสียดายที่หลายครั้งที่ไม่สามารถแก้ไขได้เนื่องจาก. NET ไม่ได้ให้การสนับสนุน AOP อย่างถูกต้อง ตอนนี้คุณสามารถ AOP เก็บแผนที่บางส่วนโดยเฉพาะอย่างยิ่งถ้าคุณใช้ MVC และเขียนตัวกรองการกระทำที่จัดการการทำแผนที่ ViewModel / DomainModel
Chris Marisic

13
ทำไม wrapper เป็นทางออกที่ดีที่สุด? สิ่งเดียวที่คุณต้องทำถ้าคุณต้องการสลับ mapper คือการใช้InjectFrom()วิธีการขยายด้วยตัวเอง
jgauffin

1
ฉันได้ลองทั้งสองอย่างแล้วและชอบ AutoMapper ฉันใช้มันเป็นส่วนเล็ก ๆ ของระบบที่ฉันจับคู่เอนทิตีกับ Linq2Sql ที่สร้างคลาส การจับคู่อย่างง่าย ๆ เป็น StockTotalQuantity -> stock_size_quantity หรือ UserId -> user_id ทำงานกับ AutoMapper โดยค่าเริ่มต้น มันไม่สามารถใช้งานได้กับ ValeInjecter แม้หลังจากเพิ่มความหนาแน่น ติดกับ AutoMapper ในตอนนี้
Artur Kędzior

27

นี่เป็นคำถามที่ฉันได้ทำการค้นคว้าด้วยเช่นกันและสำหรับกรณีการใช้งานของฉันดูเหมือนว่ามันจะเป็นสิ่งที่มีค่าสำหรับนักวิเคราะห์ มันไม่จำเป็นต้องตั้งค่าให้ใช้ก่อน (อาจกระทบกับประสิทธิภาพฉันเดาได้ว่าถึงแม้ว่าการใช้งานอย่างชาญฉลาดมันสามารถแคชการแมปสำหรับการเรียกใช้ในอนาคตแทนที่จะสะท้อนในแต่ละครั้ง) ดังนั้นคุณไม่จำเป็นต้องกำหนดการแมปใด ๆ

อย่างไรก็ตามสิ่งสำคัญที่สุดคือช่วยให้การทำแผนที่ย้อนกลับ ตอนนี้ฉันอาจจะหายไปบางสิ่งบางอย่างที่นี่เป็น Jimmy กล่าวว่าเขาไม่เห็นกรณีการใช้งานที่จำเป็นดังนั้นบางทีฉันมีรูปแบบที่ไม่ถูกต้อง แต่กรณีใช้ของฉันคือฉันกำลังสร้างวัตถุ ViewModel จาก ORM ของฉัน ฉันจะแสดงสิ่งนี้บนหน้าเว็บของฉัน เมื่อผู้ใช้เสร็จสิ้นฉันจะได้รับ ViewModel กลับคืนมาเป็น httppost สิ่งนี้จะถูกแปลงกลับไปเป็นคลาส ORM ดั้งเดิมได้อย่างไร ฉันชอบที่จะรู้ว่ารูปแบบด้วย automapper ด้วย ValueInjector มันมีความสำคัญและจะไม่ทำให้ราบเหมือนกัน เช่นการสร้างเอนทิตีใหม่

โมเดลที่สร้างขึ้นโดย entityframework (โมเดลแรก):

public partial class Family
{ 
    public int Id { get; set; }
    public string FamilyName { get; set; }

    public virtual Address Address { get; set; }
}

public partial class Address
{
    public int Id { get; set; }
    public string Line1 { get; set; }
    public string Line2 { get; set; }
    public string TownCity { get; set; }
    public string County { get; set; }
    public string Postcode { get; set; }

    public virtual Family Family { get; set; }
}

ViewModel (ซึ่งฉันสามารถตกแต่งด้วยเครื่องมือตรวจสอบ):

public class FamilyViewModel
{
    public int Id { get; set; }
    public string FamilyName { get; set; }

    public int AddressId { get; set; }
    public string AddressLine1 { get; set; }
    public string AddressLine2 { get; set; }
    public string AddressTownCity { get; set; }
    public string AddressCounty { get; set; }
    public string AddressPostcode { get; set; }
}

The ViewController:

    //
    // GET: /Family/Create

    public ActionResult Create()
    {
        return View();
    } 

    //
    // POST: /Family/Create

    [HttpPost]
    public ActionResult Create(FamilyViewModel familyViewModel)
    {
        try
        {
            Family family = new Family();
            family.InjectFrom<UnflatLoopValueInjection>(familyViewModel);
            db.Families.Add(family);
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }
    }

ในใจของฉันมันไม่ง่ายไปกว่านั้นอีกแล้ว?

(ดังนั้นนี่จึงเป็นคำถามว่าเกิดอะไรขึ้นกับรูปแบบที่ฉันพบเจอ (และดูเหมือนว่าคนอื่น ๆ จะทำ) ที่ไม่เห็นว่ามีค่าสำหรับ AutoMapper?

อย่างไรก็ตามหากรูปแบบนี้เป็นการบอกเลิกเป็นสิ่งที่คุณต้องการใช้การลงคะแนนของฉันคือค่าตัวบ่งชี้ตามไมล์ของประเทศ


1
อาจเป็นไปได้ว่าคุณควรถามคำถามนี้ในคำถามอื่นที่ติดแท็กด้วย asp.net-mvc และแนวปฏิบัติที่ดีที่สุด ViewModel ... , atm ฉันไม่เห็นปัญหาใด ๆ ตราบใดที่มันทำงานได้ดีสำหรับคุณ แต่ฉันแน่ใจว่า ใครบางคนอาจมีความคิดเห็นที่แตกต่าง
Omu

ต้องเรียนรู้ mVC เพิ่มเติม ตอนนี้ฉันสามารถตอบคำถามของฉัน วิธีการอัปเดตโมเดลดั้งเดิมเมื่อคุณได้รับโมเดลมุมมองที่ถูกใส่ข้อมูลกลับมาคือการใช้ฟังก์ชั่น UpdateModel () mvc
DanH

1
UpdateModel () ใช้เพื่อเติมข้อมูล Model ที่แทนมุมมองและเหมือนกับการทำ Action (โมเดล MyModelClasss)
Omu

เป็นจริง แต่ถ้าคุณต้องการให้มีโมเดลมุมมองแยกต่างหากตัวอย่างเช่นโมเดลพื้นที่เก็บข้อมูลก็สามารถใช้เพื่อเติมข้อมูลที่สมมติว่าการทำแผนที่นั้นไม่สำคัญ (และบ่อยครั้ง) แน่นอนว่า ValueInjector ซับซ้อนยิ่งขึ้นมาเอง
DanH

1
ฉันคิดว่าการโต้แย้งอาจทำให้คุณไม่ควรตั้งค่าคุณสมบัติของคุณบนโมเดลโดเมนของคุณ - คุณควรใช้วิธีที่เพิ่มความหมายให้กับมัน
Mike Cole
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.