Development environment:
AutoMapper:7.0.1
NetCore:2.1
Wrong content:
Unmapped members were found. Review the types and members below.
Add a custom mapping expression, ignore, add a custom resolver, or modify the source/destination type
For no matching constructor, add a no-arg ctor, add optional arguments, or map all of the constructor parameters
My Model:
public partial class XsOrdersitems
{
public int Id { get; set; }
public string ParentNo { get; set; }
public string GoodsSn { get; set; }
public string Name { get; set; }
public string Barcode { get; set; }
}
My DTO type:
public class DTOOrderItem
{
public string OrderPaNo { get; set; }
public string OrderNo { get; set; }
public string OrderNe { get; set; }
public string OrderComm { get; set; }
}
My mapping configuration:
reateMap<DTOOrderItem, XsSalesitems>()
.ForMember(d => d.Id, opt =>opt.Ignore())
.ForMember(d => d.Name, opt => { opt.MapFrom(s => s.OrderNe); })
.ForMember(d => d.GoodsSn, opt => { opt.MapFrom(s => s.OrderNo);})
.ForMember(d => d.ParentNo, opt => { opt.MapFrom(s =>s.OrderPaNo);})
.ForMember(d => d.Comment, opt => { opt.MapFrom(s => s.OrderComm); });
I tried to use opt. Ignore() to ignore the unconfigured mapping attributes, but still reported the above error, please help me, thank you for your time to answer my question.
Per your examples you are mapping to the wrong model. Your CreateMap definition is mapping DTOOrderItem to XsSalesitems, but your comments suggest you are wanting to map to XsOrderitems. Might try adding an additional CreateMap<DTOOrderItem, XsOrderitems>()... with the necessary .Ignore() references and you should be good to go.
Complete mapping definition:
CreateMap<DTOOrderItem, XsOrderitems>()
.ForMember(d => d.Id, opt => opt.Ignore())
.ForMember(d => d.Name, opt => opt.MapFrom(s => s.OrderNe))
.ForMember(d => d.GoodsSn, opt => opt.MapFrom(s => s.OrderNo))
.ForMember(d => d.ParentNo, opt => opt.MapFrom(s =>s.OrderPaNo))
.ForMember(d => d.Comment, opt => opt.MapFrom(s => s.OrderComm));
Related
I have a type that encapsulates a bunch of related data
class CollectionNoteDetails
{
CollectionNote Note {get;set;}
Customer SourceCustomer {get;set;}
Customer DestinationCustomer {get;set;}
Haulier Haulier{ get;set;}
}
and I want to flatten it
class CollectionNoteDto
{
// using fields for brevity
int Id;
DateTime CollectionDate;
// ... plus about 30 more props
string SourceCustomerName;
string DestinationCustomerName;
string HaulierName;
}
there's about 30 properties on the DTO that come off the CollectionNote, and a few that come off the other entities. The other entities are easy to handle in the CreateMap() call:
CreateMap<CollectionNoteDetails, CollectionNoteDoc>(MemberList.Destination)
.ForMember(d => d.SourceCustomerName, o => o.MapFrom(s => s.SourceCustomer.Name))
.ForMember(d => d.DestinationCustomerName, o => o.MapFrom(s => s.DestinationCustomer.Name))
.ForMember(d => d.HaulierName, o => o.MapFrom(s => s.Haulier.Name));
... but is there an easy way to map the rest of the properties to the Note source property? Something like this made up method.
CreateMap<CollectionNoteDetails, CollectionNoteDoc>(MemberList.Destination)
.MapAllByDefault(o => o.MapFrom(s => s.Note))
// other explicit mappings here
.ForMember(d => d.HaulierName, o => o.MapFrom(s => s.Haulier.Name));
You might need to recognize a prefix. The example from the documentation:
public class Source {
public int frmValue { get; set; }
public int frmValue2 { get; set; }
}
public class Dest {
public int Value { get; set; }
public int Value2 { get; set; }
}
var configuration = new MapperConfiguration(cfg => {
cfg.RecognizePrefixes("frm");
cfg.CreateMap<Source, Dest>();
});
On different matters, note that flattening is automatically supported by automapper, which means that this code:
CreateMap<CollectionNoteDetails, CollectionNoteDoc>(MemberList.Destination)
.ForMember(d => d.SourceCustomerName, o => o.MapFrom(s => s.SourceCustomer.Name))
.ForMember(d => d.DestinationCustomerName, o => o.MapFrom(s => s.DestinationCustomer.Name))
.ForMember(d => d.HaulierName, o => o.MapFrom(s => s.Haulier.Name));
is equivalent to:
CreateMap<CollectionNoteDetails, CollectionNoteDoc>(MemberList.Destination);
I have this main class with 2 complex nested objects
public class OrderData
{
public OrderDO OrderDO { get; set; }
public CustomerDO CustomerDO { get; set;
}
My OrderDO Class
public class OrderDO
{
public OrderDO()
{
OrderItemDOList = new List<OrderItemDO>();
PaymentLogDOList = new List<PaymentLogDO>();
}
public int Id { get; set; }
...
}
}
And CustomerDO Class
public class CustomerDO
{
public CustomerDO()
{
OrderDOList = new List<OrderDO>();
}
public int Id { get; set; }
...
}
Last OrderItemDO Class
public class OrderItemDO
{
public int Id { get; set; }
...
}
I cant make mapping OrderItemDOList and PaymentLogDOList under OrderDO :
OrderDO orderDO = Mapper.Map<OrderMain, OrderDO>(orderMain);
OrderItemDOList and PaymentLogDOList are null.
As mapping between complex objects is a simple thing which AutoMapper definitely does well, this leaves the likely cause of the problem as one of the following:
The source objects are not populated (lazy loading?)
You have not defined mappings between the inner objects
You can check the first item with a breakpoint on your call to Mapper.Map.
While you've not included enough code to determine if it's the second issue, you can most likely find this yourself by testing your mappings: simply run Mapper.AssertConfigurationIsValid(). If AutoMapper doesn't know how to map something you've got, it'll tell you what the problem is in the exception.
I find this way. Child Mapping types will be declared with ForMember()
method
Like This :
config.CreateMap<OrderMain, OrderDO>()
.ForMember(dest => dest.OrderItemDOList, opt => opt.ResolveUsing(fa => fa.OrderItem))
.ForMember(dest => dest.PaymentLogDOList, opt => opt.ResolveUsing(fa => fa.PaymentLog));
config.CreateMap<OrderDO, OrderMain>()
.ForMember(dest => dest.OrderItem, opt => opt.ResolveUsing(fa => fa.OrderItemDOList))
.ForMember(dest => dest.PaymentLog, opt => opt.ResolveUsing(fa => fa.PaymentLogDOList));
config.CreateMap<OrderItemDO, OrderItem>()
.ForMember(dest => dest.Id, opt => opt.ResolveUsing(fa => fa.Id))
.ForMember(dest => dest.DisplayName, opt => opt.ResolveUsing(fa => fa.DisplayName));
config.CreateMap<OrderItem, OrderItemDO>()
.ForMember(dest => dest.Id, opt => opt.ResolveUsing(fa => fa.Id))
.ForMember(dest => dest.DisplayName, opt => opt.ResolveUsing(fa => fa.DisplayName));
config.CreateMap<PaymentLog, PaymentLogDO>()
.ForMember(dest => dest.Id, opt => opt.ResolveUsing(fa => fa.Id))
.ForMember(dest => dest.OrderId, opt => opt.ResolveUsing(fa => fa.OrderId));
Is it possible to map one object to several objects using automapper? I know that it is possible to do it the other way around as shown here.
One way to do it:
Mapper.CreateMap<MAINSource, MAINDest>()
.ForMember(dest => dest.Inner1, expression => expression.ResolveUsing(source1 => source1.Inner1))
.ForMember(dest => dest.Inner2, expression => expression.ResolveUsing(source1 => source1.Inner2));
Mapper.CreateMap<Source1, Dest1>()
.ForMember(dest => dest.NumValue, expression => expression.ResolveUsing(source1 => source1.NumValue));
Mapper.CreateMap<Source1, Dest2>()
.ForMember(dest => dest.StringValue, expression => expression.ResolveUsing(source1 => source1.StringValue));
Full example:
public class Source1
{
public int NumValue { get; set; }
public string StringValue { get; set; }
}
public class MAINSource
{
public Source1 Inner1 { get; set; }
public Source1 Inner2 { get; set; }
}
public class Dest1
{
public int NumValue { get; set; }
}
public class Dest2
{
public string StringValue { get; set; }
}
public class MAINDest
{
public Dest1 Inner1 { get; set; }
public Dest2 Inner2 { get; set; }
}
Mapper.CreateMap<MAINSource, MAINDest>()
.ForMember(dest => dest.Inner1, expression => expression.ResolveUsing(source1 => source1.Inner1))
.ForMember(dest => dest.Inner2, expression => expression.ResolveUsing(source1 => source1.Inner2));
Mapper.CreateMap<Source1, Dest1>()
.ForMember(dest => dest.NumValue, expression => expression.ResolveUsing(source1 => source1.NumValue));
Mapper.CreateMap<Source1, Dest2>()
.ForMember(dest => dest.StringValue, expression => expression.ResolveUsing(source1 => source1.StringValue));
var innerSource = new Source1 {NumValue = 1, StringValue = "supervalue"};
var mainSource = new MAINSource
{
Inner1 = innerSource,
Inner2 = innerSource
};
var destination = Mapper.Map<MAINSource, MAINDest>(mainSource);
destination.Inner1.NumValue.ShouldEqual(1);
destination.Inner2.StringValue.ShouldEqual("supervalue");
I need to map to properties that are both collections of objects of the same type.
For example:
Destination:
public class MyNewObject
{
Collection TypeCollection1 { get; set; }
Collection TypeCollection2 { get; set; }
}
public class MyType
{
string Field1 { get; set; }
string Field2 { get; set; }
}
Source:
public class MyLegacyObject
{
Collection LegacyCollection1 { get; set; }
Collection LegacyCollection2 { get; set; }
}
public class MyLegacyType
{
string OldField1 { get; set; }
string OldField2 { get; set; }
}
For non-collections, I'm used to doing something like this:
Mapper.CreateMap()
.ForMember(dest => dest.TypeCollection1, opt => opt.MapFrom(
src => new Collection
{
// is there some kind of ForEach thing I can do???
Field1 = src.OldField1,
Field2 = src.OldField2
??? // this obviously doesn't work because these are the properties on MyType, not the collection
}));
Mapper.CreateMap<MyLegacyType, MyType>()
.ForMember(dest => dest.Field1, opt => opt.MapFrom(src => src.OldField1))
.ForMember(dest => dest.Field2, opt => opt.MapFrom(src => src.OldField2));
Mapper.CreateMap<MyLegacyObject, MyNewObject>()
.ForMember(dest => dest.TypeCollection1, opt => opt.MapFrom(src => src.LegacyCollection1))
.ForMember(dest => dest.TypeCollection2, opt => opt.MapFrom(src => src.LegacyCollection2))
I think I solved my own issue. This should do it.
I have a source object that looks like this:
private class SourceObject {
public Enum1 EnumProp1 { get; set; }
public Enum2 EnumProp2 { get; set; }
}
The enums are decorated with a custom [Description] attribute that provides a string representation, and I have an extension method .GetDescription() that returns it. How do I map these enum properties using that extension?
I'm trying to map to an object like this:
private class DestinationObject {
public string Enum1Description { get; set; }
public string Enum2Description { get; set; }
}
I think a custom formatter is my best bet, but I can't figure out how to add the formatter and specify which field to map from at the same time.
Argh, idiot moment. Didn't realize I could combine ForMember() and AddFormatter() like this:
Mapper.CreateMap<SourceObject, DestinationObject>()
.ForMember(x => x.Enum1Desc, opt => opt.MapFrom(x => x.EnumProp1))
.ForMember(x => x.Enum1Desc, opt => opt.AddFormatter<EnumDescriptionFormatter>())
.ForMember(x => x.Enum2Desc, opt => opt.MapFrom(x => x.EnumProp2))
.ForMember(x => x.Enum2Desc, opt => opt.AddFormatter<EnumDescriptionFormatter>());
Problem solved.