AutoMapper don't ignore null properties despite conditions - c#

Mapper.Initialize(cfg =>
{
cfg.CreateMap<ObjectDTO, Object>().ForMember(obj => obj.LastUpdateDate, opt =>
opt.Condition(pre => pre.LastUpdateDate != null));
}
obj.LastUpdateDate = Datetime.Now;
Mapper.map(objDTO,obj);
after mapping obj.LastUpdateDate will become null despite the condition I created.
happens for all members of the object.
Automapper 5.02

Are you positive LastUpdateDate is null? Datetime has a default value so if you're not expliciting setting it to null your condition won't catch it.
Try:
cfg.CreateMap<ObjectDTO, Object>()
.ForMember(dest => dest.LastUpdateDate, opt => opt.Condition(c => c.LastUpdateDate != null && c.LastUpdateDate != default(DateTime)));
Edit:
class Program
{
static void Main(string[] args)
{
Mapper.Initialize(cfg =>
{
cfg.CreateMap<ObjectDTO, Object>()
.ForMember(dest => dest.Number, opt => opt.Condition(src => src.Number.HasValue))
.ForMember(dest => dest.LastUpdateDate, opt => opt.Condition(src => src.LastUpdateDate.HasValue));
});
Mapper.AssertConfigurationIsValid();
var source = new ObjectDTO { LastUpdateDate = DateTime.Now };
var destination = new Object { Number = 10, LastUpdateDate = DateTime.Now.AddDays(-10) };
var result = Mapper.Map(source, destination);
}
}
public class ObjectDTO
{
public int? Number { get; set; }
public DateTime? LastUpdateDate { get; set; }
}
public class Object
{
public int? Number { get; set; }
public DateTime? LastUpdateDate { get; set; }
}

The condition is on the source object, not on the destination.
So with better naming for variables you are saying:
.ForMember(dest => dest.LastUpdateDate, opt => opt.Condition(src => src.LastUpdateDate != null));
So, what is in your objDTO?

Related

How to Map to abstract conditionally

I'd like to map a common object to an instance of an abstraction (concrete instance of the abstraction) without saying which concrete instance I want. I want to choose the concrete instance based on a condition which will be set up in mapping configuration.
Like here:
ConstructUsing(y => !string.IsNullOrEmpty(y.Label) ? (X)new XLabel() : new XValue())
and here:
m.Map<X>(i2); //where X is an abstraction
Data
// Source
public class Input
{
public int Id { get; set; }
public string Label { get; set; }
public decimal Amount { get; set; }
}
//Base target
public abstract class X
{
public int P1 { get; set; }
}
//Concrete target 1
public class XLabel : X
{
public string Name { get; set; }
}
//Concrete target 2
public class XValue : X
{
public string Value { get; set; }
}
CONFIGURATION:
//config
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Input, XLabel>()
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Label));
cfg.CreateMap<Input, XValue>()
.ForMember(dest => dest.Value, opt => opt.MapFrom(src => src.Amount));
cfg.CreateMap<Input, X>()
.Include<Input, XLabel>()
.Include<Input, XValue>()
.ConstructUsing(y => !string.IsNullOrEmpty(y.Label) ? (X)new XLabel() : new XValue())
.ForMember(dest => dest.P1, opt => opt.MapFrom(src => src.Id));
});
MAPPING:
//Test
Input i1 = new Input { Id = 1, Amount = 2, };
Input i2 = new Input { Id = 1, Label = "my label" };
IMapper m = new Mapper(config);
var result1 = m.Map<X>(i1);
var result2 = m.Map<X>(i2);
Notice that I'm doing this:
var result1 = m.Map<X>(i1); not this var result1 = m.Map<XValue>(i1); -And this is what I wanted to do -I wanted to Map to abstraction not to a concrete instance
TESTS:
Assert.IsType<XValue>(result1); //PASSED
Assert.IsType<XLabel>(result2); //PASSED
Assert.Equal("my label", ((XLabel)result1).Name);// Message: Assert.Equal() FAILURE Expected: my label; Actual: (null)
Problem:
Looks like this mapping does not work:
cfg.CreateMap<Input, XLabel>()
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Label));
cfg.CreateMap<Input, XValue>()
.ForMember(dest => dest.Value, opt => opt.MapFrom(src => src.Amount));
Message: Assert.Equal() FAILURE Expected: my label; Actual: (null)

Automapper - reuse of mapping rules for projection

Given 2 source entities:
class SourceA
{
public string Info1 { get; set; }
public string Info2 { get; set; }
}
class SourceB
{
public A A { get; set; }
public string OptionalExtraInfo { get; set; }
}
and one destination class:
class Dest
{
public string ModifiedInfo1 { get; set; }
public string ModifiedInfo2 { get; set; }
public string ModifiedOptionalExtraInfo { get; set; }
}
I want to have the following code working with EF6:
var destsFromA = dbContext.SourcesA.ProjectTo<Dest>().ToArray();
var destsFromB = dbContext.SourcesB.ProjectTo<Dest>().ToArray();
So I define Automapper.net mappings:
SourceA => Dest
SourceB => Dest
with custom rules on how to project Info1 into ModifiedInfo1, and Info2=>ModifiedInfo2:
CreateMap<SourceA, Dest>()
.ForMember(x => ModifiedInfo1, opt => opt.MapFrom(src => src.Info1 + " something else-1")
.ForMember(x => ModifiedInfo2, opt => opt.MapFrom(src => src.Info1 + " something else-2")
.ForMember(x => ModifiedOptionalExtraInfo, opt => opt.Ignore());
CreateMap<SourceB, Dest>()
.ForMember(x => ModifiedInfo1, opt => opt.MapFrom(src => src.A.Info1 + " something else-1")
.ForMember(x => ModifiedInfo2, opt => opt.MapFrom(src => src.A.Info2 + " something else-2")
.ForMember(x => ModifiedOptionalExtraInfo, opt => opt.MapFrom(src => src.OptionalExtraInfo + " something else-3"));
How do I reuse mapping rules for ModifiedInfo1, ModifiedInfo2 in second mapping as they are the same as in the first case?
UPDATE In my certain case I figured out how to reuse SourceA => Dest mapping in a natural way.
First, I added a reverse-reference (navigation property) SourceA.B as these entities are really in one-to-zero-or-one relationship and EF has to know about that.
Then I changed the aggregation root in my application code and it became:
var destsFromA = dbContext.SourcesA.ProjectTo<Dest>().ToArray();
var destsFromB = dbContext.SourcesB.Select(x => x.A).ProjectTo<Dest>().ToArray();
so I only had to work with the only SourceA => Dest mapping
Finally I changed the mapping itself:
CreateMap<SourceA, Dest>()
.ForMember(x => ModifiedInfo1, opt => opt.MapFrom(src => src.Info1 + " something else-1")
.ForMember(x => ModifiedInfo2, opt => opt.MapFrom(src => src.Info1 + " something else-2")
.ForMember(x => ModifiedOptionalExtraInfo, opt => opt.MapFrom(src => src.B ? src.B.OptionalExtraInfo + " something else-3" : null);
As this is a solution to a problem, but not an answer to the original question, I accepted Ilya Chumakov's answer as a correct one.
Parametrize mappings with expressions:
opt.MapFrom(expression)
.ForMember(x => x.Foo, expression)
It's easy to extract these expression variables with ReSharper, so it could look like:
Expression<Func<SourceA, string>> expression = src => src.Info1 + " something else-1";
var func = expression.Compile();
cfg.CreateMap<SourceA, Dest>()
.ForMember(x => x.ModifiedInfo1,
opt => opt.MapFrom(expression));
cfg.CreateMap<SourceB, Dest>()
.ForMember(x => x.ModifiedInfo1,
opt => opt.MapFrom(src => func(src.A)));
Update: In case of LINQ to SQL translation, the solution becomes much more complicated. expression.Compile() won't work and a new expression should be created:
Expression<Func<SourceA, string>> expression = src => src.Info1 + "foo";
//it should contain `src => src.A.Info1 + "foo"`
var newExpression = ConvertExpression(expression);
Basic implementation with ExpressionVisitor:
private static Expression<Func<SourceB, string>>
ConvertExpression(Expression<Func<SourceA, string>> expression)
{
var newParam = Expression.Parameter(typeof(SourceB), "src");
var newExpression = Expression.Lambda<Func<SourceB, string>>(
new ReplaceVisitor().Modify(expression.Body, newParam), newParam);
return newExpression;
}
class ReplaceVisitor : ExpressionVisitor
{
private ParameterExpression parameter;
public Expression Modify(Expression expression, ParameterExpression parameter)
{
this.parameter = parameter;
return Visit(expression);
}
protected override Expression VisitLambda<T>(Expression<T> node)
{
return Expression.Lambda<Func<SourceB, bool>>(
Visit(node.Body),
Expression.Parameter(typeof(SourceB)));
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (node.Type == typeof(SourceA))
{
return Expression.Property(parameter, nameof(SourceB.A));
}
throw new InvalidOperationException();
}
}
A quick and easy solution would be to use an intermediate class.
First the classes who are used then later on in the posting
public class SourceA
{
public string A { get; set; }
}
public class SourceB
{
public string B { get; set; }
}
public class Dest
{
public string ValueFromSourceA { get; set; }
public string ValueFromSourceB { get; set; }
}
That said here is the intermediate class:
public class Intermediate
{
public SourceA SourceA { get; set; } = new SourceA();
public SourceB SourceB { get; set; } = new SourceB();
}
Now let's start sticking the parts together with Automapper.
Defining profile classes
public class DestinationProfile : Profile
{
public DestinationProfile()
{
this.CreateMap<Intermediate, Dest>()
.ForMember(destination => destination.ValueFromSourceA,
opt => opt.MapFrom(src => src.SourceA.A))
.ForMember(destination => destination.ValueFromSourceB,
opt => opt.MapFrom(src => src.SourceB.B));
}
}
public class IntermediateProfile : Profile
{
public IntermediateProfile()
{
this.CreateMap<Intermediate, Dest>()
.ForMember(destination => destination.ValueFromSourceA, map => map.MapFrom(src => src.SourceA.A))
.ForMember(destination => destination.ValueFromSourceB, map => map.MapFrom(src => src.SourceB.B));
// ----- TODO: Create mapping for source classes.
}
}
And here comes the heavy lifting for the mapping we marked as todo above.
You can use IValueResolver interface from Automapper to define value mapping.
So in our case the resolvers look like
public class SourceAResolver : IValueResolver<SourceA, Intermediate, SourceA>
{
public SourceA Resolve(SourceA source, Intermediate destination, SourceA destMember, ResolutionContext context)
{
return source;
}
}
public class SourceBResolver : IValueResolver<SourceB, Intermediate, SourceB>
{
public SourceB Resolve(SourceB source, Intermediate destination, SourceB destMember, ResolutionContext context)
{
return source;
}
}
With the above now we are able to replace the todo statement
this.CreateMap<SourceA, Intermediate>()
.ForMember(destination => destination.SourceA, map => map.ResolveUsing<SourceAResolver>());
this.CreateMap<SourceB, Intermediate>()
.ForMember(destination => destination.SourceB, map => map.ResolveUsing<SourceBResolver>());
Finally we register our profile classes to the Automapper
public static class AutomapperProfile
{
public static void Configure()
{
Mapper.Initialize(cfg =>
{
cfg.AddProfile<DestinationProfile>();
cfg.AddProfile<IntermediateProfile>();
});
}
}
Firing up a console with the below code snippet helps testing our stuff
AutomapperProfile.Configure();
var a = new SourceA {A = "Value A"};
var b = new SourceB() {B = "Value B"};
var intermediate = new Intermediate() {SourceA = a, SourceB = b};
var destination = AutoMapper.Mapper.Map<Dest>(intermediate);
Console.WriteLine(destination.ValueFromSourceA);
Console.Read();
Done!
Note: The code snippets provided are just coded to demo the usage/meaning of what is meant by "intermediate" class - have not implemented the way back to the source classes.
Have fun with it :)

How to map an object with a custom constructor from a dynamic object with automapper

I'm testing automapper to see if it can do what I need in other project, so I've made some objects in a console project, simplified but that should have what I need:
public class Person
{
public Person(List<Banco> bancos)
{
this._Bancos = bancos;
}
public int Id { get; set; }
public string Nombre { get; set; }
public DNI Dni { get; set; }
private List<Banco> _Bancos;
public List<Banco> Bancos
{
get { return _Bancos; }
}
}
public class DNI
{
private DNI() { }
public DNI(DNI2 letra)
{
this._Letra = letra;
Console.WriteLine("****DNI CONSTRUCTOR****");
}
public int Id { get; set; }
public int PersonId { get; set; }
public string number { get; set; }
private DNI2 _Letra;
public DNI2 Letra
{
get { return _Letra; }
}
}
public class DNI2
{
public int Id { get; set; }
public int DNIId { get; set; }
public string letra { get; set; }
}
public class Banco
{
public int Id { get; set; }
public string number { get; set; }
}
As you can see, the objects Person and DNI have a custom cosntructor, and I setted the last one's default parameterless constructor to private.
Now, I need to map nested objects with custom constructors from dynamic objects, so I made this in the same console project:
class Program
{
static void Main(string[] args)
{
//OJO TODO: ¿Si un objeto dinamico tiene propiedades de varios tipos, es capaz de diferenciar a qué tipo pertenece cada prop?
//¿qué pasa si un valor del dinamico es del tipo equivocado?
var bancoConfig = new MapperConfiguration(cfg => cfg.CreateMissingTypeMaps = true);
var DNI2Config = new MapperConfiguration(cfg => cfg.CreateMissingTypeMaps = true);
DNI2Config.AssertConfigurationIsValid();
var bancoMapper = bancoConfig.CreateMapper();
var dni2Mapper = DNI2Config.CreateMapper();
var dni2DBConfig = new MapperConfiguration(cfg =>
{
cfg.CreateMissingTypeMaps = true;
cfg.RecognizePrefixes("DNI2");
});
var dni2DBMapper = dni2DBConfig.CreateMapper();
var DNIConfig = new MapperConfiguration(cfg =>
{
cfg.CreateMap<dynamic, DNI>()
.ConstructUsing(dyn => new DNI(dni2DBMapper.Map<DNI2>(dyn)));
/*.ForMember(dest => dest.Id, opts => opts.MapFrom<int>(src => (int)(src as IDictionary<string, object>)["Id"]))
.ForMember(dest => dest.number, opts => opts.MapFrom<string>(src => (string)(src as IDictionary<string, object>)["number"]))
.ForMember(dest => dest.PersonId, opts => opts.MapFrom<int>(src => (int)(src as IDictionary<string, object>)["PersonId"]));*/
/*cfg.CreateMap<IDictionary<string, object>, DNI>()
.ConstructUsing(dyn => new DNI(dni2DBMapper.Map<DNI2>(dyn as dynamic)))
.ForMember(dest => dest.Id, opts => opts.MapFrom<int>(src => (int)(src["Id"])))
.ForMember(dest => dest.number, opts => opts.MapFrom<string>(src => (string)(src["number"])))
.ForMember(dest => dest.PersonId, opts => opts.MapFrom<int>(src => (int)(src["PersonId"])));*/
cfg.CreateMissingTypeMaps = true;
});
var dniMapper = DNIConfig.CreateMapper();
dynamic d = new { Id = 0, number = "1234" };
Banco banco = bancoMapper.Map<Banco>(d);
Console.WriteLine("Banco: " + Environment.NewLine);
Console.WriteLine(banco.Id + Environment.NewLine + banco.number);
Console.ReadLine();
d = new { Id = 1, DNIId = 0, letra = "a" };
DNI2 dni2 = dni2Mapper.Map<DNI2>(d);
Console.WriteLine("DNI2: " + Environment.NewLine);
Console.WriteLine(dni2.Id + Environment.NewLine + dni2.DNIId + Environment.NewLine + dni2.letra);
Console.ReadLine();
d = new { Id = 2, PersonId = 5, number = "5678", DNI2Id = 2, DNIId = 2, letra = "b" };
DNI2 d2 = dni2DBMapper.Map<DNI2>(d);
DNI dni = dniMapper.Map<DNI>(d);
Console.WriteLine("DNI: " + Environment.NewLine);
Console.WriteLine(dni.Id + Environment.NewLine + dni.PersonId + Environment.NewLine + dni.number + Environment.NewLine);
Console.WriteLine("dni.dni2: "+dni.Letra.Id + Environment.NewLine + dni.Letra.DNIId + Environment.NewLine + dni.Letra.letra);
Console.ReadLine();
}
}
That gives this result in the console:
Banco:
0
1234
DNI2:
1
0
a
****DNI CONSTRUCTOR****
DNI:
2
5
5678
dni.dni2: 0
0
So, it just creates the DNI object and set the members, it go through the public constructor... but even when it goes through the constructor it doesn't set the DNI2 property.
If I coment the dynamic line in the DNI configuration:
var DNIConfig = new MapperConfiguration(cfg =>
{
cfg.CreateMap<dynamic, DNI>()
.ConstructUsing(dyn => new DNI(dni2DBMapper.Map<DNI2>(dyn)));
/*.ForMember(dest => dest.Id, opts => opts.MapFrom<int>(src => (int)(src as IDictionary<string, object>)["Id"]))
.ForMember(dest => dest.number, opts => opts.MapFrom<string>(src => (string)(src as IDictionary<string, object>)["number"]))
.ForMember(dest => dest.PersonId, opts => opts.MapFrom<int>(src => (int)(src as IDictionary<string, object>)["PersonId"]));*/
/*cfg.CreateMap<IDictionary<string, object>, DNI>()
.ConstructUsing(dyn => new DNI(dni2DBMapper.Map<DNI2>(dyn as dynamic)))
.ForMember(dest => dest.Id, opts => opts.MapFrom<int>(src => (int)(src["Id"])))
.ForMember(dest => dest.number, opts => opts.MapFrom<string>(src => (string)(src["number"])))
.ForMember(dest => dest.PersonId, opts => opts.MapFrom<int>(src => (int)(src["PersonId"])));*/
//cfg.CreateMissingTypeMaps = true;
});
... so it does not have the config to make it dynamic, the result is:
Banco:
0
1234
DNI2:
1
0
a
****DNI CONSTRUCTOR****
DNI:
0
0
dni.dni2: 2
2
b
The commented lines in the configuration is only part of what I've tried, including two days searching here and google.
Seems that the program is telling me: you map it from a dynamic or you use custom constructor, you can not do both, suck it.
The most intriguing part for me is: using the first configuration, it isn't mapping the DNI2 object, but it is mapping the DNI object using the constructor(the line is at the console), but it don't have the object needed by the parameters, so it is using the constructor without the required parameter O_o
Honestly, I know I'm an amateur and all, but I always thought that even using reflection you couldn't use a constructor(neither any other method) without any of the required parameters.
So: Is there a way to map a nested object with a custom constructor from a dynamic object with automapper?
I have found a solution to this:
var DNIDynConfig = new MapperConfiguration(cfg => cfg.CreateMissingTypeMaps = true);
var dniDynMapper = DNIDynConfig.CreateMapper();
var DNIConfig = new MapperConfiguration(cfg =>
{
cfg.CreateMap<dynamic, DNI>()
.ConstructUsing(dyn => new DNI(dni2DBMapper.Map<DNI2>(dyn)))
.AfterMap((src, dest) =>
{
dniDynMapper.Map(src, dest, typeof(object), typeof(DNI));
});
});
I don't really like it since it seems that it have to map the object twice, but it works. I would appreaciate if someone came with something better though.

AutoMapper Ignore on child collection property

I am trying to map object's of the same type which have a collection of child objects and am finding that Ignore() applied to properties on the child object seem to be umm... ignored!
Here's a unit test which demonstrates the problem.
class A
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<B> Children { get; set; }
}
class B
{
public int Id { get; set; }
public string Name { get; set; }
}
[TestClass]
public class UnitTest1
{
[TestInitialize()]
public void Initialize()
{
Mapper.CreateMap<A, A>()
.ForMember(dest => dest.Id, opt => opt.Ignore());
Mapper.CreateMap<B, B>()
.ForMember(dest => dest.Id, opt => opt.Ignore());
}
[TestMethod]
public void TestMethod1()
{
A src = new A { Id = 0, Name = "Source", Children = new List<B> { new B { Id = 0, Name = "Child Src" } } };
A dest = new A { Id = 1, Name = "Dest", Children = new List<B> { new B { Id = 11, Name = "Child Dest" } } };
Mapper.Map(src, dest);
}
After the Map call the A object's Id property is still 1, as expected, but child B object's Id property is changed from 11 to 0.
Why?
There are several bugs in AutoMapper 4.1.1.
First is about UseDestinationValue: https://github.com/AutoMapper/AutoMapper/issues/568
Second is about nested collections: https://github.com/AutoMapper/AutoMapper/issues/934
Horrifying! The workaround is to map your B instances directly:
Mapper.CreateMap<A, A>()
.ForMember(dest => dest.Id, opt => opt.Ignore())
.ForMember(dest => dest.Children, opt => opt.Ignore());
Mapper.CreateMap<B, B>()
.ForMember(dest => dest.Id, opt => opt.Condition((ResolutionContext src) => false));
and add additional mapping calls:
Mapper.Map(src, dest);
Mapper.Map(src.Children.First(), dest.Children.First()); //example!!!
You may call Mapper.Map in cycle:
for (int i = 0; i < src.Children.Count; i++)
{
var srcChild = src.Children[i];
var destChild = dest.Children[i];
Mapper.Map(srcChild, destChild);
}
This will make things work right.

Exception using AutoMapper with Entity Framework

I am trying to include Automapper into project using Entity Framework, this is my DTO class:
public class FunctionDto
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
public string Comment { get; set; }
public DateTime? ExaminationDate { get; set; }
public string Place { get; set; }
}
And domain class with code first:
public class Function
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
public string Comment { get; set; }
public DateTime? ExaminationDate { get; set; }
public string Place { get; set; }
public virtual List<Employee> Employees { get; set; }
}
Automapper configuration:
public static class AutoMapperConfiguration
{
public static void Configure()
{
Mapper.Initialize(config => config.AddProfile<FunctionProfile>());
}
}
public class FunctionProfile : Profile
{
protected override void Configure()
{
CreateMap<Function, FunctionDto>()
.ForMember(dto => dto.Id, opt => opt.MapFrom(src => src.Id))
.ForMember(dto => dto.Name, opt => opt.MapFrom(src => src.Name))
.ForMember(dto => dto.Comment, opt => opt.MapFrom(src => src.Comment))
.ForMember(dto => dto.StartDate, opt => opt.MapFrom(src => src.StartDate))
.ForMember(dto => dto.EndDate, opt => opt.MapFrom(src => src.EndDate))
.ForMember(dto => dto.ExaminationDate, opt => opt.MapFrom(src => src.ExaminationDate))
.ForMember(dto => dto.Place, opt => opt.MapFrom(src => src.Place));
}
}
Then use in WebApi:
var functionDtos = functions
.AsQueryable()
.OrderBy(sort)
.Skip(start)
.Take(count)
.ToList()
.Select(Mapper.Map<FunctionDto>);
Of course I have register in Global:
AutoMapperConfiguration.Configure();
But I got the exception:
Missing type map configuration or unsupported mapping
What is wrong with the code above?
Can you please confirm what functions is as the following passes:
MapperConfiguration.cs
namespace StackOverflow.Function
{
using AutoMapper;
public class MyProfile : Profile
{
protected override void Configure()
{
CreateMap<Function, FunctionDto>();
}
}
}
MappingTests.cs
[TestFixture]
public class MappingTests
{
[Test]
public void AutoMapper_Configuration_IsValid()
{
Mapper.Initialize(m => m.AddProfile<MyProfile>());
Mapper.AssertConfigurationIsValid();
}
[Test]
public void AutoMapper_Mapping_IsValid()
{
Mapper.Initialize(m => m.AddProfile<MyProfile>());
Mapper.AssertConfigurationIsValid();
var functions = new List<Function>
{
new Function
{
Comment = "Stack Overflow Rocks",
EndDate = new DateTime(2012, 01, 01),
ExaminationDate = new DateTime(2012, 02, 02),
Id = 1,
Name = "Number 1",
Place = "Here, there and everywhere",
StartDate = new DateTime(2012, 03, 03)
},
new Function
{
Comment = "As do I",
EndDate = new DateTime(2013, 01, 01),
ExaminationDate = new DateTime(2013, 02, 02),
Id = 2,
Name = "Number 2",
Place = "Nowhere",
StartDate = new DateTime(2013, 03, 03)
}
};
var functionDtos = functions
.AsQueryable()
.OrderBy(x => x.Id)
.Skip(1)
.Take(1)
.ToList()
.Select(Mapper.Map<FunctionDto>);
Assert.That(functionDtos, Is.Not.Null);
Assert.That(functionDtos.Count(), Is.EqualTo(1));
Assert.That(functionDtos.First().Id, Is.EqualTo(2));
}
}
Try this Configure() method,
Note: If the Function, FunctionDto has same name properties you do not need to map. AutoMapper will take care mapping.
protected override void Configure()
{
CreateMap<Function, FunctionDto>().IgnoreAllNonExisting();
}
--
public static IMappingExpression<TSource, TDestination> IgnoreAllNonExisting<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
{
var sourceType = typeof(TSource);
var destinationType = typeof(TDestination);
var existingMaps = Mapper.GetAllTypeMaps().First(x => x.SourceType.Equals(sourceType) && x.DestinationType.Equals(destinationType));
foreach (var property in existingMaps.GetUnmappedPropertyNames())
{
expression.ForMember(property, opt => opt.Ignore());
}
return expression;
}

Categories

Resources