public static void Expand <IParentEntity, IUniqueEntity>(IModel model, Func <IParentEntity, ICollection <IUniqueEntity> > accessor) where IParentEntity : IPersistEntity where IUniqueEntity : IPersistEntity
        {
            //get duplicates in one go to avoid exponential search
            var candidates = new Dictionary <IUniqueEntity, List <IParentEntity> >();

            foreach (var entity in model.Instances.OfType <IParentEntity>())
            {
                foreach (var val in accessor(entity))
                {
                    List <IParentEntity> assets;
                    if (!candidates.TryGetValue(val, out assets))
                    {
                        assets = new List <IParentEntity>();
                        candidates.Add(val, assets);
                    }
                    assets.Add(entity);
                }
            }

            var multi = candidates.Where(a => a.Value.Count > 1);
            var map   = new XbimInstanceHandleMap(model, model);

            foreach (var kvp in multi)
            {
                var value    = kvp.Key;
                var entities = kvp.Value;

                //skip the first
                for (int i = 1; i < entities.Count; i++)
                {
                    //clear map to create complete copy every time
                    map.Clear();
                    var copy = model.InsertCopy(value, map, null, false, false);

                    //remove original and add fresh copy
                    var entity     = entities[i];
                    var collection = accessor(entity);
                    collection.Remove(value);
                    collection.Add(copy);
                }
            }
        }
        /// <summary>
        /// Inserts deep copy of an object into this model. The entity must originate from the same schema (the same EntityFactory).
        /// This operation happens within a transaction which you have to handle yourself unless you set the parameter "noTransaction" to true.
        /// Insert will happen outside of transactional behaviour in that case. Resulting model is not guaranteed to be valid according to any
        /// model view definition. However, it is granted to be consistent. You can optionaly bring in all inverse relationships. Be carefull as it
        /// might easily bring in almost full model.
        ///
        /// </summary>
        /// <typeparam name="T">Type of the copied entity</typeparam>
        /// <param name="model">Model to be used as a target</param>
        /// <param name="toCopy">Entity to be copied</param>
        /// <param name="mappings">Mappings of previous inserts</param>
        /// <param name="includeInverses">Option if to bring in all inverse entities (enumerations in original entity)</param>
        /// <param name="keepLabels">Option if to keep entity labels the same</param>
        /// <param name="propTransform">Optional delegate which you can use to filter the content which will get coppied over.</param>
        /// <param name="getLabeledEntity">Functor to be used to create entity with specified label</param>
        /// <returns>Copy from this model</returns>
        public static T InsertCopy <T>(IModel model, T toCopy, XbimInstanceHandleMap mappings, PropertyTranformDelegate propTransform, bool includeInverses,
                                       bool keepLabels, Func <Type, int, IPersistEntity> getLabeledEntity) where T : IPersistEntity
        {
            try
            {
                var toCopyLabel = toCopy.EntityLabel;
                XbimInstanceHandle copyHandle;
                var toCopyHandle = new XbimInstanceHandle(toCopy);
                //try to get the value if it was created before
                if (mappings.TryGetValue(toCopyHandle, out copyHandle))
                {
                    return((T)copyHandle.GetEntity());
                }

                var expressType = model.Metadata.ExpressType(toCopy);
                var copy        = keepLabels ? getLabeledEntity(toCopy.GetType(), toCopyLabel) : model.Instances.New(toCopy.GetType());

                copyHandle = new XbimInstanceHandle(copy);
                //key is the label in original model
                mappings.Add(toCopyHandle, copyHandle);

                var props = expressType.Properties.Values.Where(p => !p.EntityAttribute.IsDerived);
                if (includeInverses)
                {
                    props = props.Union(expressType.Inverses);
                }

                foreach (var prop in props)
                {
                    var value = propTransform != null
                        ? propTransform(prop, toCopy)
                        : prop.PropertyInfo.GetValue(toCopy, null);

                    if (value == null)
                    {
                        continue;
                    }

                    var isInverse = (prop.EntityAttribute.Order == -1); //don't try and set the values for inverses
                    var theType   = value.GetType();
                    //if it is an express type or a value type, set the value
                    if (theType.GetTypeInfo().IsValueType || typeof(ExpressType).GetTypeInfo().IsAssignableFrom(theType) ||
                        theType == typeof(string))
                    {
                        prop.PropertyInfo.SetValue(copy, value, null);
                    }
                    else if (!isInverse && typeof(IPersistEntity).GetTypeInfo().IsAssignableFrom(theType))
                    {
                        prop.PropertyInfo.SetValue(copy,
                                                   InsertCopy(model, (IPersistEntity)value, mappings, propTransform, includeInverses, keepLabels, getLabeledEntity), null);
                    }
                    else if (!isInverse && typeof(IList).GetTypeInfo().IsAssignableFrom(theType))
                    {
                        var itemType = theType.GetItemTypeFromGenericType();

                        var copyColl = prop.PropertyInfo.GetValue(copy, null) as IList;
                        if (copyColl == null)
                        {
                            throw new Exception(string.Format("Unexpected collection type ({0}) found", itemType.Name));
                        }

                        foreach (var item in (IList)value)
                        {
                            var actualItemType = item.GetType();
                            if (actualItemType.GetTypeInfo().IsValueType || typeof(ExpressType).GetTypeInfo().IsAssignableFrom(actualItemType))
                            {
                                copyColl.Add(item);
                            }
                            else if (typeof(IPersistEntity).GetTypeInfo().IsAssignableFrom(actualItemType))
                            {
                                var cpy = InsertCopy(model, (IPersistEntity)item, mappings, propTransform, includeInverses,
                                                     keepLabels, getLabeledEntity);
                                copyColl.Add(cpy);
                            }
                            else if (typeof(IList).GetTypeInfo().IsAssignableFrom(actualItemType)) //list of lists
                            {
                                var listColl = (IList)item;
                                var getAt    = copyColl.GetType().GetTypeInfo().GetMethod("GetAt");
                                if (getAt == null)
                                {
                                    throw new Exception(string.Format("GetAt Method not found on ({0}) found", copyColl.GetType().Name));
                                }
                                var copyListColl = getAt.Invoke(copyColl, new object[] { copyColl.Count }) as IList;
                                if (copyListColl == null)
                                {
                                    throw new XbimException("Collection can't be used as IList");
                                }
                                foreach (var listItem in listColl)
                                {
                                    var actualListItemType = listItem.GetType();
                                    if (actualListItemType.GetTypeInfo().IsValueType ||
                                        typeof(ExpressType).GetTypeInfo().IsAssignableFrom(actualListItemType))
                                    {
                                        copyListColl.Add(listItem);
                                    }
                                    else if (typeof(IPersistEntity).GetTypeInfo().IsAssignableFrom(actualListItemType))
                                    {
                                        var cpy = InsertCopy(model, (IPersistEntity)listItem, mappings, propTransform,
                                                             includeInverses,
                                                             keepLabels, getLabeledEntity);
                                        copyListColl.Add(cpy);
                                    }
                                    else
                                    {
                                        throw new Exception(string.Format("Unexpected collection item type ({0}) found",
                                                                          itemType.Name));
                                    }
                                }
                            }
                            else
                            {
                                throw new Exception(string.Format("Unexpected collection item type ({0}) found",
                                                                  itemType.Name));
                            }
                        }
                    }
                    else if (isInverse && value is IEnumerable <IPersistEntity> ) //just an enumeration of IPersistEntity
                    {
                        foreach (var ent in (IEnumerable <IPersistEntity>)value)
                        {
                            InsertCopy(model, ent, mappings, propTransform, includeInverses, keepLabels, getLabeledEntity);
                        }
                    }
                    else if (isInverse && value is IPersistEntity) //it is an inverse and has a single value
                    {
                        InsertCopy(model, (IPersistEntity)value, mappings, propTransform, includeInverses, keepLabels, getLabeledEntity);
                    }
                    else
                    {
                        throw new Exception(string.Format("Unexpected item type ({0})  found", theType.Name));
                    }
                }
                return((T)copy);
            }
            catch (Exception e)
            {
                throw new XbimException(string.Format("General failure in InsertCopy ({0})", e.Message), e);
            }
        }