2011-07-04 73 views
15

Tôi đã được làm phẳng miền đối tượng vào DTOs như trong ví dụ dưới đây:Một cách tốt hơn để sử dụng AutoMapper để làm phẳng các đối tượng lồng nhau?

public class Root 
{ 
    public string AParentProperty { get; set; } 
    public Nested TheNestedClass { get; set; } 
} 

public class Nested 
{ 
    public string ANestedProperty { get; set; } 
} 

public class Flattened 
{ 
    public string AParentProperty { get; set; } 
    public string ANestedProperty { get; set; } 
} 

// I put the equivalent of the following in a profile, configured at application start 
// as suggested by others: 

Mapper.CreateMap<Root, Flattened>() 
     .ForMember 
     (
      dest => dest.ANestedProperty 
      , opt => opt.MapFrom(src => src.TheNestedClass.ANestedProperty) 
     ); 

// This is in my controller: 
Flattened myFlattened = Mapper.Map<Root, Flattened>(myRoot); 

tôi đã xem xét một số ví dụ, và cho đến nay điều này dường như là cách để san bằng một hệ thống phân cấp lồng nhau. Nếu đối tượng con có một số thuộc tính, tuy nhiên, cách tiếp cận này không tiết kiệm được nhiều mã.

tôi thấy ví dụ này:

http://consultingblogs.emc.com/owainwragg/archive/2010/12/22/automapper-mapping-from-multiple-objects.aspx

nhưng nó đòi hỏi các trường hợp của các đối tượng ánh xạ, theo yêu cầu của Map() chức năng, mà sẽ không làm việc với một hồ sơ như tôi hiểu nó.

Tôi mới sử dụng AutoMapper, vì vậy tôi muốn biết liệu có cách nào tốt hơn để thực hiện việc này hay không.

+0

Tôi có cùng thách thức với John. – noocyte

+0

Không ai có thể giúp đỡ về điều này? –

Trả lời

10

Trong phiên bản mới nhất của AutoMapper, có quy ước đặt tên mà bạn có thể sử dụng để tránh nhiều .Những câu lệnh thành viên.

Trong ví dụ của bạn, nếu bạn cập nhật lớp dẹt của bạn là:

public class Flattened 
{ 
    public string AParentProperty { get; set; } 
    public string TheNestedClassANestedProperty { get; set; } 
} 

Bạn có thể tránh việc sử dụng các báo cáo kết quả ForMember:

Mapper.CreateMap<Root, Flattened>(); 

Automapper sẽ (theo quy ước) Bản đồ Root.TheNestedClass.ANestedProperty để Flattened.TheNestedClassANestedProperty trong trường hợp này. Có vẻ xấu xí hơn khi bạn sử dụng tên lớp thực, trung thực!

+0

đặt tên thuộc tính mô hình quan điểm của tôi dựa trên việc sử dụng các Automapper không phải là điều tôi muốn làm. Tôi đánh giá cao câu trả lời nhưng tác dụng phụ của giải pháp sẽ khiến tôi sử dụng kỹ thuật trong câu hỏi ban đầu. – Choco

3

thêm 2 giải pháp khả thi:

Mapper.CreateMap<Nested, Flattened>() 
    .ForMember(s=>s.AParentProperty, o=>o.Ignore()); 
Mapper.CreateMap<Root, Flattened>() 
    .ForMember(d => d.ANestedProperty, o => o.MapFrom(s => s.TheNestedClass)); 

Một phương pháp khác sẽ là bên dưới, nhưng nó sẽ không vượt qua được Mapper.AssertConfigurationIsValid().

Mapper.CreateMap<Nested, Flattened>() 
//.ForMember map your properties here 
Mapper.CreateMap<Root, Flattened>() 
//.ForMember... map you properties here 
.AfterMap((s, d) => Mapper.Map(s.TheNestedClass, d)); 
+1

Cách tiếp cận tốt đẹp; quá xấu gọi 'Mapper.AssertConfigurationIsValid();' trên cấu hình này không thành công với hai lỗi (có hai bản đồ được tạo, không có bản đồ nào hoàn toàn bao gồm thuộc tính kiểu đích) –

+3

không chắc chắn cách giải quyết vấn đề này nếu có nhiều trường trong lớp lồng nhau? OP muốn tránh thêm các câu lệnh "Đối với thành viên đích", nếu có nhiều thuộc tính trong đối tượng Flattened sẽ ánh xạ từ đối tượng lồng nhau. –

+0

Nó chỉ là một thay thế cho phương pháp đặt tên công ước. Không phải lúc nào người ta cũng có khả năng thay đổi/đổi tên các thuộc tính cấu trúc xuống để tuân theo các quy ước đặt tên của AutoMapper. –

1

tôi đã viết phương pháp khuyến nông để giải quyết vấn đề tương tự:

public static IMappingExpression<TSource, TDestination> FlattenNested<TSource, TNestedSource, TDestination>(
    this IMappingExpression<TSource, TDestination> expression, 
    Expression<Func<TSource, TNestedSource>> nestedSelector, 
    IMappingExpression<TNestedSource, TDestination> nestedMappingExpression) 
{ 
    var dstProperties = typeof(TDestination).GetProperties().Select(p => p.Name); 

    var flattenedMappings = nestedMappingExpression.TypeMap.GetPropertyMaps() 
                .Where(pm => pm.IsMapped() && !pm.IsIgnored()) 
                .ToDictionary(pm => pm.DestinationProperty.Name, 
                    pm => Expression.Lambda(
                     Expression.MakeMemberAccess(nestedSelector.Body, pm.SourceMember), 
                     nestedSelector.Parameters[0])); 

    foreach (var property in dstProperties) 
    { 
     if (!flattenedMappings.ContainsKey(property)) 
      continue; 

     expression.ForMember(property, opt => opt.MapFrom((dynamic)flattenedMappings[property])); 
    } 

    return expression; 
} 

Vì vậy, trong trường hợp của bạn nó có thể được sử dụng như thế này:

var nestedMap = Mapper.CreateMap<Nested, Flattened>() 
         .IgnoreAllNonExisting(); 

Mapper.CreateMap<Root, Flattened>() 
     .FlattenNested(s => s.TheNestedClass, nestedMap); 

IgnoreAllNonExisting() là từ here.

Mặc dù nó không phải là giải pháp phổ quát, nó sẽ là đủ cho các trường hợp đơn giản.

Vì vậy,

  1. Bạn không cần phải tuân theo quy ước phẳng trong các thuộc tính đích
  2. Mapper.AssertConfigurationIsValid() sẽ vượt qua
  3. Bạn có thể sử dụng phương pháp này trong API không tĩnh (một hồ sơ) cũng như
+1

tôi không thể có được điều này để làm việc bằng cách sử dụng phiên bản mới nhất của AutoMapper. MappingExpression.TypeMap không khả dụng nữa. –

0

Để cải thiện câu trả lời khác, hãy chỉ định MemberList.Source cho cả hai ánh xạ và đặt thuộc tính lồng nhau bị bỏ qua. Xác thực rồi chuyển OK.

Mapper.Initialize(cfg => 
{ 
    cfg.CreateMap<SrcNested, DestFlat>(MemberList.Source); 
    cfg.CreateMap<SrcRoot, DestFlat>(MemberList.Source) 
     .ForSourceMember(s => s.Nested, x => x.Ignore()) 
     .AfterMap((s, d) => Mapper.Map(s.Nested, d)); 
}); 

Mapper.AssertConfigurationIsValid(); 

var dest = Mapper.Map<SrcRoot, DestFlat>(src); 
Các vấn đề liên quan