Ejemplo n.º 1
0
        /// <summary>
        ///   <para> Map all items </para>
        /// </summary>
        /// <typeparam name="TFrom"> Type to map from </typeparam>
        /// <typeparam name="TTo"> Type to map to </typeparam>
        /// <param name="from"> Object enumerable to map from </param>
        /// <param name="toExpression"> Object collection to map to </param>
        /// <param name="match"> Match function to find objects in the 'to' items given a 'from' item </param>
        /// <param name="context"> Context </param>
        public void MapAll <TFrom, TTo>(
            IEnumerable <TFrom> from,
            Expression <Func <IEnumerable <TTo> > > toExpression,
            Func <TFrom, TTo, bool> match,
            IMapperContext context)
            where TTo : class
        {
            if (toExpression == null)
            {
                throw new ArgumentNullException("toExpression");
            }
            if (from == null)
            {
                return;
            }

            var toMember
                = new CollapseMembersExpressionVisitor()
                  .Modify(toExpression);

            var toOriginal = toMember.GetValue();
            var toItemType = GetEnumerableElementType(toMember.Type);

            var toList = toOriginal as IList;

            if (toOriginal == null ||
                toList == null ||
                toList.IsFixedSize || toList.IsReadOnly)
            {
                // create a new member list when null or readonly
                toList = (IList)
                         (Implements(toMember.Type, typeof(IList)) &&
                          !toMember.Type.IsArray
                              ? Activator.CreateInstance(toMember.Type)
                              : Activator.CreateInstance(
                              typeof(Collection <>).MakeGenericType(new[] { toItemType }))
                         );

                // set it to the member, knowing it is an IEnumerable<TTo>
                toMember.SetValue((IEnumerable <TTo>)toList);
            }

            // get original 'to' items for matching, and clear from member list
            var toListOriginal = toOriginal == null
                                     ? new List <TTo>()
                                     : toOriginal.ToList();

            toList.Clear();

            // prepare to map each 'from' item
            var fromItemType = typeof(TFrom);
            var mapper       = Get(fromItemType, toItemType);
            var mapperMethod = mapper.GetType().GetMethod("Invoke");

            foreach (var fromItem in from)
            {
                // find the 'to' item or create one
                var toItem = default(TTo);
                if (match != null)
                {
                    toItem = toListOriginal
                             .SingleOrDefault(t => match(fromItem, t));

                    toListOriginal.Remove(toItem);
                }

                if (toItem == null)
                {
                    toItem = context.Create <TTo>();
                }

                // map
                mapperMethod.Invoke(mapper,
                                    new object[] { fromItem, toItem, context });

                toList.Add(toItem);

                context.Update(toItem);
            }

            if (!toListOriginal.Any())
            {
                return;
            }

            foreach (var toItem in toListOriginal)
            {
                context.Delete(toItem);
            }
        }