Example #1
0
        /// <summary>
        /// Shortcut to get an @All Entity Describing an Attribute
        /// </summary>
        private static ImportEntity GetAttributeMetaData(string name, string notes, bool? visibleInEditUi, string defaultValue = null)
        {
            var allEntity = new ImportEntity
            {
                AttributeSetStaticName = "@All",
                Values = new Dictionary<string, List<IValueImportModel>>()
            };
            if (!string.IsNullOrEmpty(name))
                allEntity.Values.Add("Name", new List<IValueImportModel> { new ValueImportModel<string>(allEntity) { Value = name } });
            if (!string.IsNullOrEmpty(notes))
                allEntity.Values.Add("Notes", new List<IValueImportModel> { new ValueImportModel<string>(allEntity) { Value = notes } });
            if (visibleInEditUi.HasValue)
                allEntity.Values.Add("VisibleInEditUI", new List<IValueImportModel> { new ValueImportModel<bool?>(allEntity) { Value = visibleInEditUi } });
            if (defaultValue != null)
                allEntity.Values.Add("DefaultValue", new List<IValueImportModel> { new ValueImportModel<string>(allEntity) { Value = defaultValue } });

            return allEntity;
        }
Example #2
0
        /// <summary>
        /// Returns an EAV import entity
        /// </summary>
        /// <param name="xEntity">xEntity to parse</param>
        /// <param name="assignmentObjectTypeId">assignmentObjectTypeId of the Entity</param>
        /// <param name="targetDimensions">all Dimensions that exist in the Target-App/Zone</param>
        /// <param name="sourceDimensions">all Dimensions that exist in the Source-App/Zone</param>
        /// <param name="sourceDefaultDimensionId">Default Dimension ID of the Surce-App/Zone</param>
        /// <param name="defaultLanguage">Default Language of the Target-App/Zone</param>
        /// <param name="keyNumber">KeyNumber of the Entity</param>
        /// <param name="keyGuid">KeyGuid of the Entity</param>
        /// <param name="keyString">KeyString of the Entity</param>
        public static ImportEntity GetImportEntity(XElement xEntity, int assignmentObjectTypeId, List<Dimension> targetDimensions, List<Dimension> sourceDimensions, int? sourceDefaultDimensionId, string defaultLanguage, int? keyNumber = null, Guid? keyGuid = null, string keyString = null)
        {
            var targetEntity = new ImportEntity
            {
                AssignmentObjectTypeId = assignmentObjectTypeId,
                AttributeSetStaticName = xEntity.Attribute("AttributeSetStaticName").Value,
                EntityGuid = Guid.Parse(xEntity.Attribute("EntityGUID").Value),
                KeyNumber = keyNumber,
                KeyGuid = keyGuid,
                KeyString = keyString
            };

            var targetValues = new Dictionary<string, List<IValueImportModel>>();

            // Group values by StaticName
            var valuesGroupedByStaticName = xEntity.Elements("Value")
                .GroupBy(v => v.Attribute("Key").Value, e => e, (key, e) => new { StaticName = key, Values = e.ToList() });

            // Process each attribute (values grouped by StaticName)
            foreach (var sourceAttribute in valuesGroupedByStaticName)
            {
                var sourceValues = sourceAttribute.Values;
                var tempTargetValues = new List<ImportValue>();

                // Process each target's language
                foreach (var targetDimension in targetDimensions.OrderByDescending(p => p.ExternalKey == defaultLanguage).ThenBy(p => p.ExternalKey))
                {
                    // This list will contain all source dimensions
                    var sourceLanguages = new List<Dimension>();

                    // Add exact match source language, if exists
                    var exactMatchSourceDimension = sourceDimensions.FirstOrDefault(p => p.ExternalKey == targetDimension.ExternalKey);
                    if (exactMatchSourceDimension != null)
                        sourceLanguages.Add(exactMatchSourceDimension);

                    // Add un-exact match language
                    var unExactMatchSourceDimensions = sourceDimensions.Where(p => p.ExternalKey != targetDimension.ExternalKey && p.ExternalKey.StartsWith(targetDimension.ExternalKey.Substring(0, 3)))
                        .OrderByDescending(p => p.ExternalKey == defaultLanguage)
                        .ThenByDescending(p => p.ExternalKey.Substring(0, 2) == p.ExternalKey.Substring(3, 2))
                        .ThenBy(p => p.ExternalKey);
                    sourceLanguages.AddRange(unExactMatchSourceDimensions);

                    // Add primary language, if current target is primary
                    if (targetDimension.ExternalKey == defaultLanguage && sourceDefaultDimensionId.HasValue)
                    {
                        var sourcePrimaryLanguage = sourceDimensions.FirstOrDefault(p => p.DimensionID == sourceDefaultDimensionId);
                        if (sourcePrimaryLanguage != null && !sourceLanguages.Contains(sourcePrimaryLanguage))
                            sourceLanguages.Add(sourcePrimaryLanguage);
                    }

                    XElement sourceValue = null;
                    var readOnly = false;

                    foreach (var sourceLanguage in sourceLanguages)
                    {
                        sourceValue = sourceValues.FirstOrDefault(p => p.Elements("Dimension").Any(d => d.Attribute("DimensionID").Value == sourceLanguage.DimensionID.ToString()));

                        if (sourceValue == null)
                            continue;

                        readOnly = Boolean.Parse(sourceValue.Elements("Dimension").FirstOrDefault(p => p.Attribute("DimensionID").Value == sourceLanguage.DimensionID.ToString()).Attribute("ReadOnly").Value);

                        // Override ReadOnly for primary target language
                        if (targetDimension.ExternalKey == defaultLanguage)
                            readOnly = false;

                        break;
                    }

                    // Take first value if there is only one value wihtout a dimension (default / fallback value), but only in primary language
                    if (sourceValue == null && sourceValues.Count == 1 && !sourceValues.Elements("Dimension").Any() && targetDimension.ExternalKey == defaultLanguage)
                        sourceValue = sourceValues.First();

                    // Process found value
                    if (sourceValue != null)
                    {
                        var dimensionsToAdd = new List<Import.ValueDimension>();
                        if (targetDimensions.Single(p => p.ExternalKey == targetDimension.ExternalKey).DimensionID >= 1)
                            dimensionsToAdd.Add(new Import.ValueDimension { DimensionExternalKey = targetDimension.ExternalKey, ReadOnly = readOnly });

                        // If value has already been added to the list, add just dimension with original ReadOnly state
                        var existingImportValue = tempTargetValues.FirstOrDefault(p => p.XmlValue == sourceValue);
                        if (existingImportValue != null)
                            existingImportValue.Dimensions.AddRange(dimensionsToAdd);
                        else
                        {
                            tempTargetValues.Add(new ImportValue
                            {
                                Dimensions = dimensionsToAdd,
                                XmlValue = sourceValue
                            });
                        }

                    }

                }

                var currentAttributesImportValues = tempTargetValues.Select(tempImportValue => ValueImportModel.GetModel(tempImportValue.XmlValue.Attribute("Value").Value, tempImportValue.XmlValue.Attribute("Type").Value, tempImportValue.Dimensions, targetEntity)).ToList();
                targetValues.Add(sourceAttribute.StaticName, currentAttributesImportValues);
            }

            targetEntity.Values = targetValues;

            return targetEntity;
        }
Example #3
0
 private ImportEntity AppendEntity(Guid entityGuid)
 {
     var entity = new ImportEntity
     {
         AttributeSetStaticName = _contentType.StaticName,
         AssignmentObjectTypeId = Configuration.AssignmentObjectTypeIdDefault,// SexyContent.SexyContent.AssignmentObjectTypeIDDefault,
         EntityGuid = entityGuid,
         KeyNumber = null,
         Values = new Dictionary<string, List<IValueImportModel>>()
     };
     Entities.Add(entity);
     return entity;
 }
Example #4
0
        private static ImportEntity GetStringAttributeMetaData(string inputType, int? rowCount)
        {
            var stringEntity = new ImportEntity
            {
                AttributeSetStaticName = "@String",
                Values = new Dictionary<string, List<IValueImportModel>>()
            };
            if (!string.IsNullOrEmpty(inputType))
                stringEntity.Values.Add("InputType", new List<IValueImportModel> { new ValueImportModel<string>(stringEntity) { Value = inputType } });
            if (rowCount.HasValue)
                stringEntity.Values.Add("RowCount", new List<IValueImportModel> { new ValueImportModel<decimal?>(stringEntity) { Value = rowCount } });

            return stringEntity;
        }
Example #5
0
        /// <summary>
        /// Import an Entity with all values
        /// </summary>
        private void PersistOneImportEntity(ImportEntity importEntity)
        {
            var cache = DataSource.GetCache(null, _context.AppId);

            #region try to get AttributeSet or otherwise cancel & log error

            // var attributeSet = Context.AttribSet.GetAttributeSet(importEntity.AttributeSetStaticName);
            var attributeSet = cache.GetContentType(importEntity.AttributeSetStaticName);
            if (attributeSet == null) // AttributeSet not Found
            {
                _importLog.Add(new ImportLogItem(EventLogEntryType.Error, "AttributeSet not found")
                {
                    ImportEntity = importEntity,
                    ImportAttributeSet = new ImportAttributeSet {StaticName = importEntity.AttributeSetStaticName}
                });
                return;
            }

            #endregion

            // Find existing Enties - meaning both draft and non-draft
            List<IEntity> existingEntities = null;
            if (importEntity.EntityGuid.HasValue)
                existingEntities = cache.LightList.Where(e => e.EntityGuid == importEntity.EntityGuid.Value).ToList();

            #region Simplest case - add (nothing existing to update)
            if (existingEntities == null || !existingEntities.Any())
            {
                _context.Entities.AddEntity(attributeSet.AttributeSetId, importEntity, _importLog, importEntity.IsPublished, null);
                return;
            }

            #endregion

            // todo: 2dm 2016-06-29 check this
            #region Another simple case - we have published entities, but are saving unpublished - so we create a new one

            if (!importEntity.IsPublished && existingEntities.Count(e => e.IsPublished == false) == 0 && !importEntity.ForceNoBranch)
            {
                var publishedId = existingEntities.First().EntityId;
                _context.Entities.AddEntity(attributeSet.AttributeSetId, importEntity, _importLog, importEntity.IsPublished, publishedId);
                return;
            }

            #endregion 
             
            #region Update-Scenario - much more complex to decide what to change/update etc.

            #region Do Various Error checking like: Does it really exist, is it not draft, ensure we have the correct Content-Type

            // Get existing, published Entity
            var editableVersionOfTheEntity = existingEntities.OrderBy(e => e.IsPublished ? 1 : 0).First(); // get draft first, otherwise the published
            _importLog.Add(new ImportLogItem(EventLogEntryType.Information, "Entity already exists", importEntity));
        

            #region ensure we don't save a draft is this is not allowed (usually in the case of xml-import)

            // Prevent updating Draft-Entity - since the initial would be draft if it has one, this would throw
            if (PreventUpdateOnDraftEntities && !editableVersionOfTheEntity.IsPublished)
            {
                _importLog.Add(new ImportLogItem(EventLogEntryType.Error, "Importing a Draft-Entity is not allowed", importEntity));
                return;
            }

            #endregion

            #region Ensure entity has same AttributeSet (do this after checking for the draft etc.
            if (editableVersionOfTheEntity.Type.StaticName != importEntity.AttributeSetStaticName)
            {
                _importLog.Add(new ImportLogItem(EventLogEntryType.Error, "Existing entity (which should be updated) has different ContentType", importEntity));
                return;
            }
            #endregion



            #endregion

            var newValues = importEntity.Values;
            if (_dontUpdateExistingAttributeValues) // Skip values that are already present in existing Entity
                newValues = newValues.Where(v => editableVersionOfTheEntity.Attributes.All(ev => ev.Value.Name != v.Key))
                    .ToDictionary(v => v.Key, v => v.Value);

            _context.Entities.UpdateEntity(editableVersionOfTheEntity.RepositoryId, newValues, updateLog: _importLog,
                preserveUndefinedValues: _keepAttributesMissingInImport, isPublished: importEntity.IsPublished, forceNoBranch: importEntity.ForceNoBranch);

            #endregion
        }
Example #6
0
 public ImportLogItem(EventLogEntryType entryType, string message, ImportEntity importEntity = null)
 {
     EntryType = entryType;
     Message = message;
     ImportEntity = importEntity;
 }
Example #7
0
        private ImportEntity CreateImportEntity(EntityWithHeader editInfo, int appId)
        {
            var newEntity = editInfo.Entity;
            var metadata = editInfo.Header.Metadata;

            #region initial data quality checks
            if (newEntity.Id == 0 && newEntity.Guid == Guid.Empty)
                throw new Exception("Item must have a GUID");
            #endregion

            // TODO 2tk: Refactor code - we use methods from XML import extensions!
            var importEntity = new ImportEntity();

            #region Guids, Ids, Published, Content-Types
            importEntity.EntityGuid = newEntity.Guid;
            importEntity.IsPublished = newEntity.IsPublished;
            // 2dm 2016-06-29
            importEntity.ForceNoBranch = !newEntity.IsBranch; // if it's not a branch, it should also force no branch...
            importEntity.AttributeSetStaticName = newEntity.Type.StaticName;
            #endregion

            #region Metadata if we have any
            importEntity.AssignmentObjectTypeId = Constants.DefaultAssignmentObjectTypeId;  // default case
            if (metadata != null && metadata.HasMetadata)
            {
                importEntity.AssignmentObjectTypeId = metadata.TargetType;
                importEntity.KeyGuid = metadata.KeyGuid;
                importEntity.KeyNumber = metadata.KeyNumber;
                importEntity.KeyString = metadata.KeyString;
            }
            #endregion

            // Attributes
            importEntity.Values = new Dictionary<string, List<IValueImportModel>>();

            // only transfer the fields / values which exist in the content-type definition
            var attributeSet = DataSource.GetCache(null, appId).GetContentType(newEntity.Type.StaticName);
            foreach (var attribute in newEntity.Attributes)
            {
                var attDef = attributeSet[attribute.Key];
                var attributeType = attDef.Type;

                // don't save anything of the type empty - this is heading-only
                if(attributeType == AttributeTypeEnum.Empty.ToString())
                    continue;

                foreach (var value in attribute.Value.Values)
                {
                    var importValue = importEntity.AppendAttributeValue(attribute.Key, value.Value, attributeType);

                    if (value.Dimensions == null)
                    {   // TODO2tk: Must this be done to save entities
                        importValue.AppendLanguageReference("", false);
                        continue;
                    }
                    foreach (var dimension in value.Dimensions)
                    {
                        importValue.AppendLanguageReference(dimension.Key, dimension.Value);
                    }
                }
            }

            return importEntity;
        }
Example #8
0
File: V7.cs Project: 2sic/2sxc
        /// <summary>
        /// Add ContentTypes for ContentGroup and move all 2sxc data to EAV
        /// </summary>
        internal void Version070000()
        {
            logger.LogStep("07.00.00", "Start", false);

            var userName = "******";

            #region 1. Import new ContentTypes for ContentGroups and Templates

            logger.LogStep("07.00.00", "1. Import new ContentTypes for ContentGroups and Templates", false);
            if (DataSource.GetCache(Constants.DefaultZoneId, Constants.MetaDataAppId).GetContentType("2SexyContent-Template") == null)
            {

                var xmlToImport =
                    File.ReadAllText(HttpContext.Current.Server.MapPath("~/DesktopModules/ToSIC_SexyContent/Upgrade/07.00.00.xml"));
                //var xmlToImport = File.ReadAllText("../../../../Upgrade/07.00.00.xml");
                var xmlImport = new XmlImport("en-US", userName, true);
                var success = xmlImport.ImportXml(Constants.DefaultZoneId, Constants.MetaDataAppId, XDocument.Parse(xmlToImport));

                if (!success)
                {
                    var messages = String.Join("\r\n- ", xmlImport.ImportLog.Select(p => p.Message).ToArray());
                    throw new Exception("The 2sxc module upgrade to 07.00.00 failed: " + messages);
                }
            }

            #endregion

            // 2. Move all existing data to the new ContentTypes - Append new IDs to old data (ensures that we can fix things that went wrong after upgrading the module)

            #region Prepare Templates
            logger.LogStep("07.00.00", "2. Move all existing data to the new ContentTypes - Append new IDs to old data (ensures that we can fix things that went wrong after upgrading the module)", false);

            var sqlConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["SiteSqlServer"].ConnectionString);
            var templates = new DataTable();
            const string sqlCommand = @"SELECT        ToSIC_SexyContent_Templates.TemplateID, ToSIC_SexyContent_Templates.PortalID, ToSIC_SexyContent_Templates.Name, ToSIC_SexyContent_Templates.Path,
                         ToSIC_SexyContent_Templates.AttributeSetID, ToSIC_SexyContent_Templates.DemoEntityID, ToSIC_SexyContent_Templates.Script,
                         ToSIC_SexyContent_Templates.IsFile, ToSIC_SexyContent_Templates.Type, ToSIC_SexyContent_Templates.IsHidden, ToSIC_SexyContent_Templates.Location,
                         ToSIC_SexyContent_Templates.UseForList, ToSIC_SexyContent_Templates.UseForItem, ToSIC_SexyContent_Templates.SysCreated,
                         ToSIC_SexyContent_Templates.SysCreatedBy, ToSIC_SexyContent_Templates.SysModified, ToSIC_SexyContent_Templates.SysModifiedBy,
                         ToSIC_SexyContent_Templates.SysDeleted, ToSIC_SexyContent_Templates.SysDeletedBy, ToSIC_SexyContent_Templates.AppID,
                         ToSIC_SexyContent_Templates.PublishData, ToSIC_SexyContent_Templates.StreamsToPublish, ToSIC_SexyContent_Templates.PipelineEntityID,
                         ToSIC_SexyContent_Templates.ViewNameInUrl, ToSIC_SexyContent_Templates.Temp_PresentationTypeID,
                         ToSIC_SexyContent_Templates.Temp_PresentationDemoEntityID, ToSIC_SexyContent_Templates.Temp_ListContentTypeID,
                         ToSIC_SexyContent_Templates.Temp_ListContentDemoEntityID, ToSIC_SexyContent_Templates.Temp_ListPresentationTypeID,
                         ToSIC_SexyContent_Templates.Temp_ListPresentationDemoEntityID, ToSIC_SexyContent_Templates.Temp_NewTemplateGuid, ToSIC_EAV_Apps.ZoneID,
                         ToSIC_EAV_Entities_1.EntityGUID AS ContentDemoEntityGuid, ToSIC_EAV_Entities_2.EntityGUID AS PresentationDemoEntityGuid,
                         ToSIC_EAV_Entities_3.EntityGUID AS ListContentDemoEntityGuid, ToSIC_EAV_Entities_4.EntityGUID AS ListPresentationDemoEntityGuid,
                         ToSIC_EAV_Entities.EntityGUID AS PipelineEntityGuid
            FROM            ToSIC_SexyContent_Templates INNER JOIN
                         ToSIC_EAV_Apps ON ToSIC_SexyContent_Templates.AppID = ToSIC_EAV_Apps.AppID LEFT OUTER JOIN
                         ToSIC_EAV_Entities ON ToSIC_SexyContent_Templates.PipelineEntityID = ToSIC_EAV_Entities.EntityID LEFT OUTER JOIN
                         ToSIC_EAV_Entities AS ToSIC_EAV_Entities_3 ON ToSIC_SexyContent_Templates.Temp_ListContentDemoEntityID = ToSIC_EAV_Entities_3.EntityID LEFT OUTER JOIN
                         ToSIC_EAV_Entities AS ToSIC_EAV_Entities_1 ON ToSIC_SexyContent_Templates.DemoEntityID = ToSIC_EAV_Entities_1.EntityID LEFT OUTER JOIN
                         ToSIC_EAV_Entities AS ToSIC_EAV_Entities_2 ON
                         ToSIC_SexyContent_Templates.Temp_PresentationDemoEntityID = ToSIC_EAV_Entities_2.EntityID LEFT OUTER JOIN
                         ToSIC_EAV_Entities AS ToSIC_EAV_Entities_4 ON ToSIC_SexyContent_Templates.Temp_ListPresentationDemoEntityID = ToSIC_EAV_Entities_4.EntityID
            WHERE        (ToSIC_SexyContent_Templates.SysDeleted IS NULL) AND ((SELECT COUNT(*) FROM ToSIC_EAV_Entities WHERE EntityGUID = ToSIC_SexyContent_Templates.Temp_NewTemplateGuid) = 0)";

            var adapter = new SqlDataAdapter(sqlCommand, sqlConnection);
            adapter.SelectCommand.CommandTimeout = 3600;
            adapter.Fill(templates);

            var existingTemplates = templates.AsEnumerable().Select(t =>
            {
                var templateId = (int)t["TemplateID"];
                var zoneId = (int)t["ZoneID"];
                var appId = (int)t["AppID"];
                var cache = ((BaseCache)DataSource.GetCache(zoneId, appId)).GetContentTypes();

                #region Helper Functions
                Func<int?, string> getContentTypeStaticName = contentTypeId =>
                {
                    if (!contentTypeId.HasValue || contentTypeId == 0)
                        return "";
                    if (cache.Any(c => c.Value.AttributeSetId == contentTypeId))
                        return cache[contentTypeId.Value].StaticName;
                    return "";
                };

                #endregion

                // Create anonymous object to validate the types
                var tempTemplate = new
                {
                    TemplateID = templateId,
                    Name = (string)t["Name"],
                    Path = (string)t["Path"],
                    NewEntityGuid = Guid.Parse((string)t["Temp_NewTemplateGuid"]),
                    //AlreadyImported = t["Temp_NewTemplateGuid"] != DBNull.Value,

                    ContentTypeId = getContentTypeStaticName(t["AttributeSetID"] == DBNull.Value ? new int?() : (int)t["AttributeSetID"]),
                    ContentDemoEntityGuids = t["ContentDemoEntityGuid"] == DBNull.Value ? new List<Guid>() : new List<Guid> { (Guid)t["ContentDemoEntityGuid"] },
                    PresentationTypeId = getContentTypeStaticName((int)t["Temp_PresentationTypeID"]),
                    PresentationDemoEntityGuids = t["PresentationDemoEntityGuid"] == DBNull.Value ? new List<Guid>() : new List<Guid> { (Guid)t["PresentationDemoEntityGuid"] },
                    ListContentTypeId = getContentTypeStaticName((int)t["Temp_ListContentTypeID"]),
                    ListContentDemoEntityGuids = t["ListContentDemoEntityGuid"] == DBNull.Value ? new List<Guid>() : new List<Guid> { (Guid)t["ListContentDemoEntityGuid"] },
                    ListPresentationTypeId = getContentTypeStaticName((int)t["Temp_ListPresentationTypeID"]),
                    ListPresentationDemoEntityGuids = t["ListPresentationDemoEntityGuid"] == DBNull.Value ? new List<Guid>() : new List<Guid> { (Guid)t["ListPresentationDemoEntityGuid"] },

                    Type = (string)t["Type"],
                    IsHidden = (bool)t["IsHidden"],
                    Location = (string)t["Location"],
                    UseForList = (bool)t["UseForList"],
                    AppId = appId,
                    PublishData = (bool)t["PublishData"],
                    StreamsToPublish = (string)t["StreamsToPublish"],
                    PipelineEntityGuids = t["PipelineEntityGuid"] == DBNull.Value ? new List<Guid>() : new List<Guid> { (Guid)t["PipelineEntityGuid"] },
                    ViewNameInUrl = t["ViewNameInUrl"].ToString(),
                    ZoneId = zoneId
                };

                return tempTemplate;
            }).ToList();

            #endregion

            #region Prepare ContentGroups
            logger.LogStep("07.00.00", "2. Prepare Content Groups", false);

            var contentGroupItemsTable = new DataTable();
            const string sqlCommandContentGroups = @"SELECT DISTINCT        ToSIC_SexyContent_ContentGroupItems.ContentGroupItemID, ToSIC_SexyContent_ContentGroupItems.ContentGroupID,
                         ToSIC_SexyContent_ContentGroupItems.TemplateID, ToSIC_SexyContent_ContentGroupItems.SortOrder, ToSIC_SexyContent_ContentGroupItems.Type,
                         ToSIC_SexyContent_ContentGroupItems.SysCreated, ToSIC_SexyContent_ContentGroupItems.SysCreatedBy, ToSIC_SexyContent_ContentGroupItems.SysModified,
                         ToSIC_SexyContent_ContentGroupItems.SysModifiedBy, ToSIC_SexyContent_ContentGroupItems.SysDeleted,
                         ToSIC_SexyContent_ContentGroupItems.SysDeletedBy, ToSIC_SexyContent_Templates.AppID, ToSIC_EAV_Apps.ZoneID,
                         ToSIC_EAV_Entities.EntityGUID, ToSIC_SexyContent_ContentGroupItems.EntityID, ToSIC_SexyContent_ContentGroupItems.Temp_NewContentGroupGuid, ToSIC_SexyContent_Templates.Temp_NewTemplateGuid
            FROM            ToSIC_SexyContent_Templates INNER JOIN
                         ModuleSettings INNER JOIN
                         ToSIC_SexyContent_ContentGroupItems ON ModuleSettings.SettingValue = ToSIC_SexyContent_ContentGroupItems.ContentGroupID ON
                         ToSIC_SexyContent_Templates.TemplateID = ToSIC_SexyContent_ContentGroupItems.TemplateID INNER JOIN
                         ToSIC_EAV_Apps ON ToSIC_SexyContent_Templates.AppID = ToSIC_EAV_Apps.AppID LEFT OUTER JOIN
                         ToSIC_EAV_Entities ON ToSIC_SexyContent_ContentGroupItems.EntityID = ToSIC_EAV_Entities.EntityID
            WHERE        (ToSIC_SexyContent_ContentGroupItems.SysDeleted IS NULL) AND (ModuleSettings.SettingName = N'ContentGroupID') AND
                         ((SELECT COUNT(*) FROM ToSIC_EAV_Entities WHERE EntityGUID = ToSIC_SexyContent_ContentGroupItems.Temp_NewContentGroupGuid) = 0) ORDER BY SortOrder";

            var adapterContentGroups = new SqlDataAdapter(sqlCommandContentGroups, sqlConnection);
            adapterContentGroups.SelectCommand.CommandTimeout = 3600;
            adapterContentGroups.Fill(contentGroupItemsTable);

            var contentGroupItems = contentGroupItemsTable.AsEnumerable().Select(c => new
            {
                ContentGroupId = (int)c["ContentGroupID"],
                NewContentGroupGuid = Guid.Parse((string)c["Temp_NewContentGroupGuid"]),
                EntityId = c["EntityID"] == DBNull.Value ? new int?() : (int)c["EntityID"],
                EntityGuid = c["EntityGUID"] == DBNull.Value ? (Guid?)null : ((Guid)c["EntityGUID"]),
                TemplateId = c["TemplateID"] == DBNull.Value ? new int?() : (int)c["TemplateID"],
                SortOrder = (int)c["SortOrder"],
                Type = (string)c["Type"],
                AppId = (int)c["AppID"],
                ZoneId = (int)c["ZoneID"],
                TemplateEntityGuids = new List<Guid>() { Guid.Parse((string)c["Temp_NewTemplateGuid"]) }
            });

            var existingContentGroups = contentGroupItems.GroupBy(c => c.ContentGroupId, c => c, (id, items) =>
            {
                var itemsList = items.ToList();
                var contentGroup = new
                {
                    NewEntityGuid = itemsList.First().NewContentGroupGuid,
                    itemsList.First().AppId,
                    itemsList.First().ZoneId,
                    ContentGroupId = id,
                    TemplateGuids = itemsList.First().TemplateEntityGuids,
                    ContentGuids = itemsList.Where(p => p.Type == Constants.ContentKey).Select(p => p.EntityGuid).ToList(),
                    PresentationGuids = itemsList.Where(p => p.Type == Constants.PresentationKey).Select(p => p.EntityGuid).ToList(),
                    ListContentGuids = itemsList.Where(p => p.Type == "ListContent").Select(p => p.EntityGuid).ToList(),
                    ListPresentationGuids = itemsList.Where(p => p.Type == "ListPresentation").Select(p => p.EntityGuid).ToList()
                };
                return contentGroup;
            }).ToList();

            #endregion

            // Import all entities
            logger.LogStep("07.00.00", "2. Import all entities", false);
            var apps = existingTemplates.Select(p => p.AppId).ToList();
            apps.AddRange(existingContentGroups.Select(p => p.AppId));
            apps = apps.Distinct().ToList();

            foreach (var app in apps)
            {
                logger.LogStep("07.00.00", "Starting to migrate data for app " + app + "...");

                var currentApp = app;
                var entitiesToImport = new List<ImportEntity>();

                foreach (var t in existingTemplates.Where(t => t.AppId == currentApp))
                {
                    var entity = new ImportEntity
                    {
                        AttributeSetStaticName = "2SexyContent-Template",
                        EntityGuid = t.NewEntityGuid,
                        IsPublished = true,
                        AssignmentObjectTypeId = ContentTypeHelpers.AssignmentObjectTypeIDDefault
                    };
                    entity.Values = new Dictionary<string, List<IValueImportModel>>
                    {
                        {"Name", new List<IValueImportModel> {new ValueImportModel<string>(entity) { Value = t.Name }}},
                        {"Path", new List<IValueImportModel> {new ValueImportModel<string>(entity) { Value = t.Path }}},
                        {"ContentTypeStaticName", new List<IValueImportModel> {new ValueImportModel<string>(entity) { Value = t.ContentTypeId }}},
                        {"ContentDemoEntity", new List<IValueImportModel> {new ValueImportModel<List<Guid>>(entity) { Value = t.ContentDemoEntityGuids }}},
                        {"PresentationTypeStaticName", new List<IValueImportModel> {new ValueImportModel<string>(entity) { Value = t.PresentationTypeId }}},
                        {"PresentationDemoEntity", new List<IValueImportModel> {new ValueImportModel<List<Guid>>(entity) { Value = t.PresentationDemoEntityGuids }}},
                        {"ListContentTypeStaticName", new List<IValueImportModel> {new ValueImportModel<string>(entity) { Value = t.ListContentTypeId }}},
                        {"ListContentDemoEntity", new List<IValueImportModel> {new ValueImportModel<List<Guid>>(entity) { Value = t.ListContentDemoEntityGuids }}},
                        {"ListPresentationTypeStaticName", new List<IValueImportModel> {new ValueImportModel<string>(entity) { Value = t.ListPresentationTypeId }}},
                        {"ListPresentationDemoEntity", new List<IValueImportModel> {new ValueImportModel<List<Guid>>(entity) { Value = t.ListPresentationDemoEntityGuids }}},
                        {"Type", new List<IValueImportModel> {new ValueImportModel<string>(entity) { Value = t.Type }}},
                        {"IsHidden", new List<IValueImportModel> {new ValueImportModel<bool?>(entity) { Value = t.IsHidden }}},
                        {"Location", new List<IValueImportModel> {new ValueImportModel<string>(entity) { Value = t.Location }}},
                        {"UseForList", new List<IValueImportModel> {new ValueImportModel<bool?>(entity) { Value = t.UseForList }}},
                        {"PublishData", new List<IValueImportModel> {new ValueImportModel<bool?>(entity) { Value = t.PublishData }}},
                        {"StreamsToPublish", new List<IValueImportModel> {new ValueImportModel<string>(entity) { Value = t.StreamsToPublish }}},
                        {"Pipeline", new List<IValueImportModel> {new ValueImportModel<List<Guid>>(entity) { Value = t.PipelineEntityGuids }}},
                        {"ViewNameInUrl", new List<IValueImportModel> {new ValueImportModel<string>(entity) { Value = t.ViewNameInUrl }}}
                    };
                    entitiesToImport.Add(entity);
                }

                foreach (var t in existingContentGroups.Where(t => t.AppId == app))
                {
                    var entity = new ImportEntity
                    {
                        AttributeSetStaticName = "2SexyContent-ContentGroup",
                        EntityGuid = t.NewEntityGuid,
                        IsPublished = true,
                        AssignmentObjectTypeId = ContentTypeHelpers.AssignmentObjectTypeIDDefault
                    };
                    entity.Values = new Dictionary<string, List<IValueImportModel>>
                    {
                        {"Template", new List<IValueImportModel> {new ValueImportModel<List<Guid>>(entity) { Value = t.TemplateGuids }}},
                        {Constants.ContentKey, new List<IValueImportModel> {new ValueImportModel<List<Guid?>>(entity) { Value = t.ContentGuids }}},
                        {Constants.PresentationKey, new List<IValueImportModel> {new ValueImportModel<List<Guid?>>(entity) { Value = t.PresentationGuids }}},
                        {"ListContent", new List<IValueImportModel> {new ValueImportModel<List<Guid?>>(entity) { Value = t.ListContentGuids }}},
                        {"ListPresentation", new List<IValueImportModel> {new ValueImportModel<List<Guid?>>(entity) { Value = t.ListPresentationGuids }}}
                    };
                    entitiesToImport.Add(entity);
                }

                var import = new Eav.Import.Import(null, app, userName);
                import.RunImport(null, entitiesToImport);

                logger.LogStep("07.00.00", "Migrated data for app " + app);
            }
            logger.LogStep("07.00.00", "Done", false);
        }