Automapper: validation exception ignoring destination property - c#

I have troubles trying to ignore a destination property
Source class:
public class ClassDto
{
public int Id { get; set; }
}
Destination class:
public class ClassModel
{
public int Id { get; set; }
public IList<string> ListString { get; set; }
}
Example:
public class Program
{
static void Main(string[] args)
{
var dto = new ClassDto { Id = 1 };
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<ClassDto, ClassModel>().
ForMember(i => i.ListString, opt => opt.DoNotUseDestinationValue());
});
config.AssertConfigurationIsValid();
var mapper = config.CreateMapper();
var model = mapper.Map<ClassDto, ClassModel>(dto);
}
}
Unfortunately config.AssertConfigurationIsValid(); rises an exception:
$exception {"\nUnmapped members were found. Review the types and members below.\nAdd a custom mapping expression, ignore, add a custom
resolver, or modify the source/destination type\nFor no matching
constructor, add a no-arg ctor, add optional arguments, or map all of
the constructor
parameters\n===================================================\r\nClassDto
-> ClassModel (Destination member list)\r\nAutoMapperFoo.ClassDto -> AutoMapperFoo.ClassModel (Destination member list)\r\n\r\nUnmapped
properties:\r\nListString\r\n"} AutoMapper.AutoMapperConfigurationException
I can't undesrtand why, I explicit to ignore ListString by DoNotUseDestinationValue
Thanks in advance

By default, AutoMapper tries to map all the properties from the source
type to the destination type when both source and destination type
property names are the same. If you want some of the properties not to map
with the destination type property then you need to use the AutoMapper
Ignore Property in C#. Learn more AutoMapper Ignore Property in C#
Automapper gives the property Ignore which tells the mapper to not
take the value of a property from the source class. Ignore not only
ignore the mapping for the property, but also ignore the mapping of
all inner properties. It means that if the property is not a primitive
type, but another class, that if you are using Ignore, this class
properties won't be mapped. So, A.B.C would be A.Null.
So try using this:
.ForMember(x => x.ListString, opt => opt.Ignore())

Related

Unable to resolve mapper issue using Automapper

I have two classes in my code except one data member everything is same. But, not getting how to resolve this issue using Automapper. Can someone please throw some light on this.
Class A{ public string Id; public List Values; };
Class B{ public string Id; public List Items; };
Class C{ public string Value; public string Name; public string Dept; };
CreateMap<A, B>(); - This is giving following error while doing unit test, 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
Explicit AutoMapper Property Mapping
CreateMap<A,B>()
.ForMember(dest => dest.Items,
opt => opt.MapFrom(src => src.Values));
Reference

AutoMapper unmapped Property by using expression mapping

I try to map business objects to persistence objects using expression mapping.
I was able to simplify the problem to this simple usage of AutoMapper.
Classes to map:
public class X
{
public X(string name) => this.Name = name;
public string Name { get; }
}
public class Y
{
public string Name { get; set; }
}
These classes are very simple but shows the problem. X is immutable. That's no problem for AutoMapper. I created a map like:
var mapperConfig = new MapperConfiguration(
cfg =>
{
cfg.CreateMap<X, Y>().ReverseMap();
});
var mapper = mapperConfig.CreateMapper();
This works as expected in this case:
var yInstances = new List<Y> { new Y { Name = "Foo" } }; // Just to have some instances.
var xInstances = yInstances.Select(mapper.Map<X>).ToList();
As expected I got a List of X-Instances.
But I tried to use it as IQueryable<T> using expression mapping:
Expression<Func<X, bool>> filter = item => item.Name == "Foo";
// this line thows exception
yInstances.AsQueryable().Where(mapper.MapExpression<Expression<Func<Y, bool>>>(filter)).ToList();
The last line throws an exception containing this message:
Unhandled exception. AutoMapper.AutoMapperConfigurationException:
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
=======
Y -> X (None member list)
Y -> X (None member list)
Unmapped properties:
Name
There is no unmapped property because mapper.Map<X> is working.
I tried to add .ForCtorParam("name", opt => opt.MapFrom(src => src.Name)). But this doesn't work - not surprising.
What am I doing wrong? I'm pretty sure that this is only a single step but I'm unable to find it. Sorry.
The Code is on .Net Fiddle that illustrates the problem.

Deep cloning via Automapper ignoring specific property from the hierarchy

I have fairly simple question regarding Automapper mapping definition. My intent is to deep clone an object via Automapper while ignoring 'Id' property, this is why i have chosen it to customize the mapping.
public interface IEntity<T>
{
T Id { get; }
}
public abstract class Entity : IEntity<Guid>
{
public Guid Id { get; set; }
}
All my entities are deriving from Entity class and i simply wants to ignore all Id property in the nested hierarchy of my object without being so explicit about the mapping definition.
So far i have come up with the following piece of code to do the cloning but how to ignore Id property mapping for the nested properties and not just for the root.
public static T AutomapperClone<T>(this T source)
where T : IEntity<Guid>
{
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<T, T>()
.ForMember(d => d.Id, o => o.Ignore());
});
// checking configuration validity
config.AssertConfigurationIsValid();
// creating mapper
var mapper = config.CreateMapper();
var copy = mapper.Map<T, T>(source);
return copy;
}
The idea is that all entities get their new Id instead of using the same mapped ones. Is it accomplishable via Automapper?
Appreciate your feedback.
I wouldn't use Automapper for this person, try AnyClone to do this. It does deep cloning and can ignore by property name which seems to be what you are looking for.

How to configure a mapping of collection types with AutoMapper?

For example, I've implemented two classes like these:
public class A
{
public List<C> Items { get; set; }
}
public class B
{
public IImmutableList<C> Items { get; set; }
}
public class C
{
}
When I try to map A to B and vice versa, I get an exception because List<string> cannot be converted to IImmutable<string>.
Probably I could provide a mapping for A<->B, but since it'll be a very common pattern in my solution, I'd like to avoid to manually mapping each class that may fall into the same case.
Is there anyway I can generalize the whole mapping using generic type definitions from a collection type to another collection type?
This is what I want to avoid
mapperConfig.CreateMap<A, B>()
.ForMember(a => a.Items, opts => opts.Ignore())
.AfterMap
(
(source, target) =>
{
target.Items = source.Items.ToImmutableList();
}
);

AutoMapper include all properties of a custom List<T>

class SomeObject
{
public string name {get;set;}
}
class CustomCollection : List<SomeObject>
{
public int x {get;set;}
public string z {get;set;}
}
class A
{
public CustomCollection collection { get ; set; }
}
class B
{
public CustomCollection collection { get ; set; }
}
// Creating mapping
Mapper.CreateMap<A, B>();
When I Map A to B, all properties get mapped correctly except X and Z in CustomCollection.
CustomCollection correctly gets the List of SomeObject initialized and SomeObject.Name is also mapped correctly.
Only the custom properties X, Z that I've declared in the collection do not get mapped.
What am I doing wrong?
Only way I've found is to do an after mapping like below, but then it kinda defeats the purpose of using automapper and it breaks everytime I add a new property to CustomCollection.
Mapper.CreateMap<A, B>().AfterMap((source, destination) => {
source.x = destination.x;
source.z = destination.z ;
});
Your current mapping configuration does create a new CustomCollection but the SomeObject items inside are references to the objects in the source collection. If that's not an issue you can use the following mapping configuration:
CreateMap<CustomCollection, CustomCollection>()
.AfterMap((source, dest) => dest.AddRange(source));
CreateMap<A, B>();
If your are also fine with b.collection referencing to a.collection you could use the following mapping configuration:
CreateMap<CustomCollection, CustomCollection>()
.ConstructUsing(col => col);
CreateMap<A, B>();
AutoMapper is not designed for cloning so if you need that you must write your own logic for that.

Categories