Permalink
Browse files

Updating docs

  • Loading branch information...
jbogard committed Sep 26, 2018
1 parent 2ec8d92 commit 5ccb53d1cc2675d7cedc9f9c9008f7bf5b402ddf
@@ -86,3 +86,45 @@ The `Func`-based overload accepts more parameters, so you may have to add the pa
### Motivation
Simplify overloads, and to make it clear that you cannot have separate configuration for LINQ projections vs. in-memory mapping.
## ResolveUsing
The `ResolveUsing` method consolidated with `MapFrom`:
```c#
// IMappingExpression
// Old
void ResolveUsing(Func<TSource, TDestination> mappingFunction);
void ResolveUsing(Func<TSource, TDestination, TDestination> mappingFunction);
void ResolveUsing<TResult>(Func<TSource, TDestination, TMember, TResult> mappingFunction);
// Many, many overloads
void MapFrom(Expression<Func<TSource, TDestination>> mapExpression);
// New
void MapFrom(Expression<Func<TSource, TDestination>> mappingExpression);
void MapFrom<TResult>(Func<TSource, TDestination, TResult> mappingFunction);
void MapFrom<TResult>(Func<TSource, TDestination, TMember, TResult> mappingFunction);
```
To migrate, replace all usages of `ResolveUsing` with `MapFrom`.
The `MapFrom` expression-based method will be used for both in-memory mapping and LINQ projections. You cannot have separate configuration for in-memory vs. LINQ projections.
### Existing `ResolveUsing` usages
The change from `Func` to `Expression` may break some existing usages. Namely:
- `ResolveUsing` using lambda statements, method groups, or delegates
- Dual configuration of `ResolveUsing` and `MapFrom`
For the first case, you may either:
- Convert to a lambda expression
- Move to the `Func`-based overloads
The `Func`-based overloads accept more parameters, so you may have to add the parameters to your delegates.
### Motivation
Simplify overloads, and to make it clear that you cannot have separate configuration for LINQ projections vs. in-memory mapping.
@@ -24,7 +24,7 @@ Mapper.Initialize(cfg => {
## Preconditions
Similarly, there is a PreCondition method. The difference is that it runs sooner in the mapping process, before the source value is resolved (think MapFrom or ResolveUsing). So the precondition is called, then we decide which will be the source of the mapping (resolving), then the condition is called and finally the destination value is assigned.
Similarly, there is a PreCondition method. The difference is that it runs sooner in the mapping process, before the source value is resolved (think MapFrom). So the precondition is called, then we decide which will be the source of the mapping (resolving), then the condition is called and finally the destination value is assigned.
You can [see the steps](Understanding-your-mapping.html) yourself.
@@ -38,16 +38,16 @@ public class CustomResolver : IValueResolver<Source, Destination, int>
Once we have our IValueResolver implementation, we'll need to tell AutoMapper to use this custom value resolver when resolving a specific destination member. We have several options in telling AutoMapper a custom value resolver to use, including:
* ResolveUsing\<TValueResolver\>
* ResolveUsing(typeof(CustomValueResolver))
* ResolveUsing(aValueResolverInstance)
* MapFrom\<TValueResolver\>
* MapFrom(typeof(CustomValueResolver))
* MapFrom(aValueResolverInstance)
In the below example, we'll use the first option, telling AutoMapper the custom resolver type through generics:
```c#
Mapper.Initialize(cfg =>
cfg.CreateMap<Source, Destination>()
.ForMember(dest => dest.Total, opt => opt.ResolveUsing<CustomResolver>()));
.ForMember(dest => dest.Total, opt => opt.MapFrom<CustomResolver>()));
Mapper.AssertConfigurationIsValid();
var source = new Source
@@ -82,7 +82,7 @@ If we don't want AutoMapper to use reflection to create the instance, we can sup
```c#
Mapper.Initialize(cfg => cfg.CreateMap<Source, Destination>()
.ForMember(dest => dest.Total,
opt => opt.ResolveUsing(new CustomResolver())
opt => opt.MapFrom(new CustomResolver())
));
```
@@ -96,10 +96,10 @@ By default, AutoMapper passes the source object to the resolver. This limits the
Mapper.Initialize(cfg => {
cfg.CreateMap<Source, Destination>()
.ForMember(dest => dest.Total,
opt => opt.ResolveUsing<CustomResolver, decimal>(src => src.SubTotal));
opt => opt.MapFrom<CustomResolver, decimal>(src => src.SubTotal));
cfg.CreateMap<OtherSource, OtherDest>()
.ForMember(dest => dest.OtherTotal,
opt => opt.ResolveUsing<CustomResolver, decimal>(src => src.OtherSubTotal));
opt => opt.MapFrom<CustomResolver, decimal>(src => src.OtherSubTotal));
});
public class CustomResolver : IMemberValueResolver<object, object, decimal, decimal> {
@@ -120,8 +120,8 @@ Mapper.Map<Source, Dest>(src, opt => opt.Items["Foo"] = "Bar");
This is how to setup the mapping for this custom resolver
```c#
Mapper.CreateMap<Source, Dest>()
.ForMember(dest => dest.Foo, opt => opt.ResolveUsing((src, dest, destMember, context) => context.Items["Foo"]));
cfg.CreateMap<Source, Dest>()
.ForMember(dest => dest.Foo, opt => opt.MapFrom((src, dest, destMember, context) => context.Items["Foo"]));
```
### ForPath
@@ -120,7 +120,7 @@ public class SomeProfile : Profile
public SomeProfile()
{
var map = CreateMap<MySourceType, MyDestinationType>();
map.ForMember(d => d.PropertyThatDependsOnIoc, opt => opt.ResolveUsing<PropertyThatDependsOnIocValueResolver>());
map.ForMember(d => d.PropertyThatDependsOnIoc, opt => opt.MapFrom<PropertyThatDependsOnIocValueResolver>());
}
}
@@ -87,7 +87,7 @@ This map through AutoMapper will result in a SELECT N+1 problem, as each child `
### Custom projection
In the case where members names don't line up, or you want to create calculated property, you can use MapFrom (and not ResolveUsing) to supply a custom expression for a destination member:
In the case where members names don't line up, or you want to create calculated property, you can use MapFrom (the expression-based overload) to supply a custom expression for a destination member:
```c#
Mapper.Initialize(cfg => cfg.CreateMap<Customer, CustomerDto>()
@@ -101,21 +101,21 @@ If the expression is rejected from your query provider (Entity Framework, NHiber
### Custom Type Conversion
Occasionally, you need to completely replace a type conversion from a source to a destination type. In normal runtime mapping, this is accomplished via the ConvertUsing method. To perform the analog in LINQ projection, use the ProjectUsing method:
Occasionally, you need to completely replace a type conversion from a source to a destination type. In normal runtime mapping, this is accomplished via the ConvertUsing method. To perform the analog in LINQ projection, use the ConvertUsing method:
```c#
cfg.CreateMap<Source, Dest>().ProjectUsing(src => new Dest { Value = 10 });
cfg.CreateMap<Source, Dest>().ConvertUsing(src => new Dest { Value = 10 });
```
`ProjectUsing` is slightly more limited than `ConvertUsing` as only what is allowed in an Expression and the underlying LINQ provider will work.
The expression-based `ConvertUsing` is slightly more limited than Func-based `ConvertUsing` overloads as only what is allowed in an Expression and the underlying LINQ provider will work.
### Custom destination type constructors
If your destination type has a custom constructor but you don't want to override the entire mapping, use the ConstructProjectionUsing method:
If your destination type has a custom constructor but you don't want to override the entire mapping, use the ConstructUsing expression-based method overload:
```c#
cfg.CreateMap<Source, Dest>()
.ConstructProjectionUsing(src => new Dest(src.Value + 10));
.ConstructUsing(src => new Dest(src.Value + 10));
```
AutoMapper will automatically match up destination constructor parameters to source members based on matching names, so only use this method if AutoMapper can't match up the destination constructor properly, or if you need extra customization during construction.
@@ -194,7 +194,7 @@ However, using a dictionary will result in hard-coded values in the query instea
### Supported mapping options
Not all mapping options can be supported, as the expression generated must be interpreted by a LINQ provider. Only what is supported by LINQ providers is supported by AutoMapper:
* MapFrom
* MapFrom (Expression-based)
* Ignore
* UseValue
* NullSubstitute
@@ -204,7 +204,7 @@ Not supported:
* DoNotUseDestinationValue
* SetMappingOrder
* UseDestinationValue
* ResolveUsing
* MapFrom (Func-based)
* Before/AfterMap
* Custom resolvers
* Custom type converters
@@ -101,21 +101,21 @@ public void MapFrom(Type valueResolverType)
PropertyMapActions.Add(pm => pm.ValueResolverConfig = config);
}
public void MapFrom(Type valueResolverType, string memberName)
public void MapFrom(Type valueResolverType, string sourceMemberName)
{
var config = new ValueResolverConfiguration(valueResolverType, valueResolverType.GetGenericInterface(typeof(IMemberValueResolver<,,,>)))
{
SourceMemberName = memberName
SourceMemberName = sourceMemberName
};
PropertyMapActions.Add(pm => pm.ValueResolverConfig = config);
}
public void MapFrom<TSource, TDestination, TSourceMember, TDestMember>(IMemberValueResolver<TSource, TDestination, TSourceMember, TDestMember> resolver, string memberName)
public void MapFrom<TSource, TDestination, TSourceMember, TDestMember>(IMemberValueResolver<TSource, TDestination, TSourceMember, TDestMember> resolver, string sourceMemberName)
{
var config = new ValueResolverConfiguration(resolver, typeof(IMemberValueResolver<TSource, TDestination, TSourceMember, TDestMember>))
{
SourceMemberName = memberName
SourceMemberName = sourceMemberName
};
PropertyMapActions.Add(pm => pm.ValueResolverConfig = config);
@@ -80,39 +80,39 @@ public void MapFrom<TSourceMember>(IMemberValueResolver<TSource, TDestination, T
PropertyMapActions.Add(pm => pm.ValueResolverConfig = config);
}
public void MapFrom<TResult>(Func<TSource, TDestination, TResult> resolver)
public void MapFrom<TResult>(Func<TSource, TDestination, TResult> mappingFunction)
{
PropertyMapActions.Add(pm =>
{
Expression<Func<TSource, TDestination, TMember, ResolutionContext, TResult>> expr = (src, dest, destMember, ctxt) => resolver(src, dest);
Expression<Func<TSource, TDestination, TMember, ResolutionContext, TResult>> expr = (src, dest, destMember, ctxt) => mappingFunction(src, dest);
pm.CustomResolver = expr;
});
}
public void MapFrom<TResult>(Func<TSource, TDestination, TMember, TResult> resolver)
public void MapFrom<TResult>(Func<TSource, TDestination, TMember, TResult> mappingFunction)
{
PropertyMapActions.Add(pm =>
{
Expression<Func<TSource, TDestination, TMember, ResolutionContext, TResult>> expr = (src, dest, destMember, ctxt) => resolver(src, dest, destMember);
Expression<Func<TSource, TDestination, TMember, ResolutionContext, TResult>> expr = (src, dest, destMember, ctxt) => mappingFunction(src, dest, destMember);
pm.CustomResolver = expr;
});
}
public void MapFrom<TResult>(Func<TSource, TDestination, TMember, ResolutionContext, TResult> resolver)
public void MapFrom<TResult>(Func<TSource, TDestination, TMember, ResolutionContext, TResult> mappingFunction)
{
PropertyMapActions.Add(pm =>
{
Expression<Func<TSource, TDestination, TMember, ResolutionContext, TResult>> expr = (src, dest, destMember, ctxt) => resolver(src, dest, destMember, ctxt);
Expression<Func<TSource, TDestination, TMember, ResolutionContext, TResult>> expr = (src, dest, destMember, ctxt) => mappingFunction(src, dest, destMember, ctxt);
pm.CustomResolver = expr;
});
}
public void MapFrom<TSourceMember>(Expression<Func<TSource, TSourceMember>> sourceMember)
public void MapFrom<TSourceMember>(Expression<Func<TSource, TSourceMember>> mapExpression)
{
MapFromUntyped(sourceMember);
MapFromUntyped(mapExpression);
}
internal void MapFromUntyped(LambdaExpression sourceExpression)
@@ -121,10 +121,10 @@ internal void MapFromUntyped(LambdaExpression sourceExpression)
PropertyMapActions.Add(pm => pm.MapFrom(sourceExpression));
}
public void MapFrom(string sourceMember)
public void MapFrom(string sourceMemberName)
{
_sourceType.GetFieldOrProperty(sourceMember);
PropertyMapActions.Add(pm => pm.MapFrom(sourceMember));
_sourceType.GetFieldOrProperty(sourceMemberName);
PropertyMapActions.Add(pm => pm.MapFrom(sourceMemberName));
}
public void UseValue<TValue>(TValue value)
@@ -70,37 +70,35 @@ void MapFrom<TValueResolver>()
/// Map destination member using a custom function. Access both the source and destination object.
/// </summary>
/// <remarks>Not used for LINQ projection (ProjectTo)</remarks>
/// <param name="resolver">Callback function to resolve against source type</param>
void MapFrom<TResult>(Func<TSource, TDestination, TResult> resolver);
/// <param name="mappingFunction">Function to map to destination member</param>
void MapFrom<TResult>(Func<TSource, TDestination, TResult> mappingFunction);
/// <summary>
/// Map destination member using a custom function. Access the source, destination object, and source member.
/// </summary>
/// <remarks>Not used for LINQ projection (ProjectTo)</remarks>
/// <param name="resolver">Callback function to resolve against source type</param>
void MapFrom<TResult>(Func<TSource, TDestination, TMember, TResult> resolver);
/// <param name="mappingFunction">Function to map to destination member</param>
void MapFrom<TResult>(Func<TSource, TDestination, TMember, TResult> mappingFunction);
/// <summary>
/// Map destination member using a custom function. Access the source, destination object, source member, and context.
/// </summary>
/// <remarks>Not used for LINQ projection (ProjectTo)</remarks>
/// <param name="resolver">Callback function to resolve against source type</param>
void MapFrom<TResult>(Func<TSource, TDestination, TMember, ResolutionContext, TResult> resolver);
/// <param name="mappingFunction">Function to map to destination member</param>
void MapFrom<TResult>(Func<TSource, TDestination, TMember, ResolutionContext, TResult> mappingFunction);
/// <summary>
/// Specify the source member to map from. Can only reference a member on the <typeparamref name="TSource"/> type
/// Any null reference exceptions in this expression will be ignored (similar to flattening behavior)
/// Map destination member using a custom expression. Used in LINQ projection (ProjectTo).
/// </summary>
/// <typeparam name="TSourceMember">Member type of the source member to use</typeparam>
/// <param name="sourceMember">Expression referencing the source member to map against</param>
void MapFrom<TSourceMember>(Expression<Func<TSource, TSourceMember>> sourceMember);
/// <param name="mapExpression">Map expression</param>
void MapFrom<TSourceMember>(Expression<Func<TSource, TSourceMember>> mapExpression);
/// <summary>
/// Specify the source member to map from. Can only reference a member on the <typeparamref name="TSource"/> type
/// Any null reference exceptions in this expression will be ignored (similar to flattening behavior)
/// </summary>
/// <param name="property">Property name referencing the source member to map against</param>
void MapFrom(string property);
/// <param name="sourceMemberName">Property name referencing the source member to map against</param>
void MapFrom(string sourceMemberName);
/// <summary>
/// Ignore this member for configuration validation and skip during mapping
@@ -288,16 +286,16 @@ public interface IMemberConfigurationExpression : IMemberConfigurationExpression
/// </summary>
/// <remarks>Not used for LINQ projection (ProjectTo)</remarks>
/// <param name="valueResolverType">Value resolver type</param>
/// <param name="memberName">Member to supply to value resolver</param>
void MapFrom(Type valueResolverType, string memberName);
/// <param name="sourceMemberName">Member to supply to value resolver</param>
void MapFrom(Type valueResolverType, string sourceMemberName);
/// <summary>
/// Map destination member using a custom value resolver instance
/// </summary>
/// <remarks>Not used for LINQ projection (ProjectTo)</remarks>
/// <param name="valueResolver">Value resolver instance to use</param>
/// <param name="memberName">Source member to supply to value resolver</param>
void MapFrom<TSource, TDestination, TSourceMember, TDestMember>(IMemberValueResolver<TSource, TDestination, TSourceMember, TDestMember> valueResolver, string memberName);
/// <param name="sourceMemberName">Source member to supply to value resolver</param>
void MapFrom<TSource, TDestination, TSourceMember, TDestMember>(IMemberValueResolver<TSource, TDestination, TSourceMember, TDestMember> valueResolver, string sourceMemberName);
/// <summary>
/// Specify a value converter type to convert from the matching source member to the destination member

0 comments on commit 5ccb53d

Please sign in to comment.