5

Automapper 可以轻松处理将一个对象类型列表映射到另一个不同对象类型列表,但是是否可以使用 ID 作为键将其映射到现有列表?

4

2 回答 2

7

我没有找到比以下更好的方法。

这里是来源和目的地。

public class Source
{
    public int Id { get; set; } 
    public string Foo { get; set; }
}

public class Destination 
{ 
    public int Id { get; set; }
    public string Foo { get; set; }
}

定义转换器(您应该将 List<> 更改为您使用的任何类型)。

public class CollectionConverter: ITypeConverter<List<Source>, List<Destination>>
{
    public List<Destination> Convert(ResolutionContext context)
    {
        var destinationCollection = (List<Destination>)context.DestinationValue;
        if(destinationCollection == null)
            destinationCollection = new List<Destination>();
        var sourceCollection = (List<Source>)context.SourceValue;
        foreach(var source in sourceCollection)
        {
            Destination matchedDestination = null;

            foreach(var destination in destinationCollection)
            {
                if(destination.Id == source.Id)
                {
                    Mapper.Map(source, destination);
                    matchedDestination = destination;
                    break;
                }
            }
            if(matchedDestination == null)
                destinationCollection.Add(Mapper.Map<Destination>(source));
        }
        return destinationCollection;
    }
}

这是实际的映射配置和示例。

Mapper.CreateMap<Source,Destination>();
Mapper.CreateMap<List<Source>,List<Destination>>().ConvertUsing(new CollectionConverter());

var sourceCollection = new List<Source>
{
    new Source{ Id = 1, Foo = "Match"},
    new Source{ Id = 2, Foo = "DoesNotMatchWithDestination"}
};
var destinationCollection = new List<Destination>
{
    new Destination{ Id = 1, Foo = "Match"},
    new Destination{ Id = 3, Foo = "DoeNotMatchWithSource"}
};
var mergedCollection = Mapper.Map(sourceCollection, destinationCollection);

您应该得到以下结果。

映射结果

于 2012-07-11T20:35:36.610 回答
1

我发现这篇文章非常有用,因此我想我会在我的类型转换器的通用版本中进行反馈,您可以使用它来从每个对象中选择要匹配的属性。

使用它,您需要做的就是:

// Example of usage
Mapper.CreateMap<UserModel, User>();
var converter = CollectionConverterWithIdentityMatching<UserModel, User>.Instance(model => model.Id, user => user.Id);
Mapper.CreateMap<List<UserModel>, List<User>>().ConvertUsing(converter);

//The actual converter
public class CollectionConverterWithIdentityMatching<TSource, TDestination> : 
    ITypeConverter<List<TSource>, List<TDestination>> where TDestination : class
{
    private readonly Func<TSource, object> sourcePrimaryKeyExpression;
    private readonly Func<TDestination, object> destinationPrimaryKeyExpression;

    private CollectionConverterWithIdentityMatching(Expression<Func<TSource, object>> sourcePrimaryKey, Expression<Func<TDestination, object>> destinationPrimaryKey)
    {
        this.sourcePrimaryKeyExpression = sourcePrimaryKey.Compile();
        this.destinationPrimaryKeyExpression = destinationPrimaryKey.Compile();
    }

    public static CollectionConverterWithIdentityMatching<TSource, TDestination> 
        Instance(Expression<Func<TSource, object>> sourcePrimaryKey, Expression<Func<TDestination, object>> destinationPrimaryKey)
    {
        return new CollectionConverterWithIdentityMatching<TSource, TDestination>(
            sourcePrimaryKey, destinationPrimaryKey);
    }

    public List<TDestination> Convert(ResolutionContext context)
    {
        var destinationCollection = (List<TDestination>)context.DestinationValue ?? new List<TDestination>();
        var sourceCollection = (List<TSource>)context.SourceValue;
        foreach (var source in sourceCollection)
        {
            TDestination matchedDestination = default(TDestination);

            foreach (var destination in destinationCollection)
            {
                var sourcePrimaryKey = GetPrimaryKey(source, this.sourcePrimaryKeyExpression);
                var destinationPrimaryKey = GetPrimaryKey(destination, this.destinationPrimaryKeyExpression);

                if (string.Equals(sourcePrimaryKey, destinationPrimaryKey, StringComparison.OrdinalIgnoreCase))
                {
                    Mapper.Map(source, destination);
                    matchedDestination = destination;
                    break;
                }
            }

            if (matchedDestination == null)
            {
                destinationCollection.Add(Mapper.Map<TDestination>(source));
            }
        }

        return destinationCollection;
    }

    private string GetPrimaryKey<TObject>(object entity, Func<TObject, object> expression)
    {
        var tempId = expression.Invoke((TObject)entity);
        var id = System.Convert.ToString(tempId);
        return id;
    }
}
于 2013-08-05T13:12:31.427 回答