Converting Media Types

Vote:
 

We have several thousands of PDF files in our CMS environment and until now, we did not have a specific Media Type for these files. Now we have created a type for PDFs that contains all the properties of the GenericMedia type and some additional properties but we need to figure out a way to convert the existing PDF files to the new type.

I found this article which addresses pretty much the same scenario but I'm wondering if there's a better way than manipulating the DB directly?

https://robertlinde.se/episerver%207.5/mediadata/plugin/2014/05/01/converting-mediadata-contenttype-in-episerver-75.html

#197933
Oct 17, 2018 14:37
Vote:
 

manipulating db directly wil definitely be the fastest way to do it. another option is to do it programmatically - meaning that you read pdf media types and convert to proper newly created media type in code.

#198021
Oct 19, 2018 4:53
Vote:
 

The converting to new media type in code is basically the part I'm struggling with. I'm currently getting all the PDF files for processing with this method:

 

private List<BasicContent> GetPdfs()
        {
            var pdfs = new List<BasicContent>();
            var assets = ContentRepository.GetDescendents(SiteDefinition.Current.GlobalAssetsRoot);

            OnStatusChanged("Found " + assets.Count() + " assets");

            foreach (var asset in assets)
            {
                BasicContent pdf = null;
                if (ContentRepository.TryGet(asset, out pdf) && pdf.Name.EndsWith(".pdf"))
                {
                    pdfs.Add(pdf);
                }
            }

            return pdfs;
        } 

I'm using BasicContent because if I use the new PdfFile media type, nothing gets added to the list. I'm then processing the list in a scheduled job where I check whether the ContentTypeID matches the new media types ID and if not, I try to change the content type.

protected override string ExtendedExecute()
        {
            var pdfs = GetPdfs();

            var output = new StringBuilder();

            //Get a suitable MediaData type from extension
            var mediaType = MediaDataResolver.GetFirstMatching(".pdf");
            var contentType = ContentTypeRepository.Load(mediaType);

            foreach (var pdf in pdfs)
            {
                if (pdf.ContentTypeID != contentType.ID)
                {
                    try
                    {
                        var writable = pdf.CreateWritableClone() as BasicContent;

                        if (writable != null)
                        {
                            writable.ContentTypeID = contentType.ID;

                            ContentRepository.Save(
                            writable,
                            SaveAction.Publish,
                            AccessLevel.NoAccess);
                        } else
                        {
                            output.AppendLine(string.Format("Create clone resulted in null: {0}",pdf.ContentLink.ID));
                        }
                    }
                    catch (Exception ex)
                    {
                        output.AppendLine(string.Format("ID: {0}, Error: {1}",
                            pdf.ContentLink.ID,
                            ex.Message));
                    }
                }
            }

            return string.Format(
                "Fixed {0} pdfs. \n Errors:\n{1}",
                i,
                output);
        }


This however does not convert the the type for the files but there are no exceptions either. So it seems that the conversion should be done some other way?

#198064
Oct 19, 2018 13:19
Vote:
 

I just had a case where a duplicate Image-type had been added and think I hopefully solved it the database way.

It's a bit weird how uploaded images had been distributed between the types by the way... It would've been nicer if first type in had gotten the upper hand.

Don't try this! Warning!!! Warning!!! Be sure to be backed up etc. You might break something. Risk is yours!!!

It would've also been nice to have this and block types built-in to the convert type tool... The Stored Procedures seem to work fine so this code might help someone but please be aware this is on your own risk.

BEGIN TRANSACTION [ConvertTransaction]
BEGIN TRY
  DECLARE @FromPropertyID1 int
  DECLARE @ToPropertyID1 int
  DECLARE @FromPropertyID2 int
  DECLARE @ToPropertyID2 int
  DECLARE @FromPropertyID3 int
  DECLARE @ToPropertyID3 int
  
  DECLARE @RC int
  DECLARE @PageID int
  DECLARE @FromPageType int
  DECLARE @ToPageType int
  DECLARE @Recursive bit
  DECLARE @IsTest bit

  SELECT @PageID = 1
  SELECT @FromPageType = pkID FROM tblContentType WHERE ContentTypeGUID = '0a89e464-56d4-449f-aea8-2bf774ab8730'
  SELECT @ToPageType = pkID FROM tblContentType WHERE ContentTypeGUID = '40ed0421-2d37-4751-97dc-c7ea7033c3a5'
  
  SELECT @FromPropertyID1 = pkID FROM tblPropertyDefinition WHERE fkContentTypeID = @FromPageType AND [Name] = 'Copyright'
  SELECT @FromPropertyID2 = pkID FROM tblPropertyDefinition WHERE fkContentTypeID = @FromPageType AND [Name] = 'Description'
  SELECT @FromPropertyID3 = pkID FROM tblPropertyDefinition WHERE fkContentTypeID = @FromPageType AND [Name] = 'MediumThumbnail'
  
  SELECT @ToPropertyID1 = pkID FROM tblPropertyDefinition WHERE fkContentTypeID = @ToPageType AND [Name] = 'Copyright'
  SELECT @ToPropertyID2 = pkID FROM tblPropertyDefinition WHERE fkContentTypeID = @ToPageType AND [Name] = 'Description'
  SELECT @ToPropertyID3 = pkID FROM tblPropertyDefinition WHERE fkContentTypeID = @ToPageType AND [Name] = 'MediumThumbnail'
  
  SET @Recursive = 1
  SET @IsTest = 0
  
  print @PageID
  print @FromPageType
  print @ToPageType
  
  DECLARE @MasterLanguageID int

  SET @MasterLanguageID = 8
  
  EXECUTE @RC = [dbo].[netConvertPropertyForPageType]
     @PageID
    ,@FromPageType
    ,@FromPropertyID1
    ,@ToPropertyID1
    ,@Recursive
    ,@MasterLanguageID
    ,@IsTest

  print @RC
  
  EXECUTE @RC = [dbo].[netConvertPropertyForPageType]
     @PageID
    ,@FromPageType
    ,@FromPropertyID2
    ,@ToPropertyID2
    ,@Recursive
    ,@MasterLanguageID
    ,@IsTest

  print @RC

  EXECUTE @RC = [dbo].[netConvertPropertyForPageType]
     @PageID
    ,@FromPageType
    ,@FromPropertyID3
    ,@ToPropertyID3
    ,@Recursive
    ,@MasterLanguageID
    ,@IsTest

  print @RC
  
  EXECUTE @RC = [dbo].[netConvertPageType]
     @PageID
    ,@FromPageType
    ,@ToPageType
    ,@Recursive
    ,@IsTest
  
  print @RC

  COMMIT TRANSACTION [ConvertTransaction]
END TRY
BEGIN CATCH
  ROLLBACK TRANSACTION [ConvertTransaction]
END CATCH

#201567
Feb 22, 2019 13:26
Vote:
 

I was lucky in the sense that our GenericMedia type did not have any custom properties, so I could actually just change the contenttype in the DB and everything worked.

Here's the scheduled job I built for the migration:

    public class FixPdfMediaType : ExtendedJobBase
    {
        private readonly IContentRepository ContentRepository;
        private readonly IContentTypeRepository ContentTypeRepository;
        private readonly ContentMediaResolver MediaDataResolver;

        public FixPdfMediaType()
        {
            ContentRepository = ServiceLocator.Current.GetInstance<IContentRepository>();
            ContentTypeRepository = ServiceLocator.Current.GetInstance<IContentTypeRepository>();
            MediaDataResolver = ServiceLocator.Current.GetInstance<ContentMediaResolver>();
        }

        private List<BasicContent> GetPdfs()
        {
            var pdfs = new List<BasicContent>();
            var assets = ContentRepository.GetDescendents(SiteDefinition.Current.GlobalAssetsRoot);

            OnStatusChanged("Found " + assets.Count() + " assets");

            foreach (var asset in assets)
            {
                BasicContent pdf = null;
                if (ContentRepository.TryGet(asset, out pdf) && pdf.Name.EndsWith(".pdf"))
                {
                    pdfs.Add(pdf);
                }
            }

            return pdfs;
        } 

        protected override string ExtendedExecute()
        {
            var pdfs = GetPdfs();

            OnStatusChanged("Handling " + pdfs.Count() + " PDF files");

            var output = new StringBuilder();
            int i = 0;

            //Get a suitable MediaData type from extension
            var mediaType = MediaDataResolver.GetFirstMatching(".pdf");
            var contentType = ContentTypeRepository.Load(mediaType);

            foreach (var pdf in pdfs)
            {
                if (pdf.ContentTypeID != contentType.ID)
                {
                    OnStatusChanged("Changing type for " + pdf.Name);

                    try
                    {
                        using (SqlConnection conn =
                                    new SqlConnection(ConfigurationManager.ConnectionStrings["EPiServerDB"].ConnectionString))
                        {
                            conn.Open();
                            using (SqlCommand cmd =
                                new SqlCommand("UPDATE tblPage SET fkPageTypeID=@ContentTypeID WHERE PkId = @ID", conn))
                            {
                                cmd.Parameters.AddWithValue("@ContentTypeID", contentType.ID);
                                cmd.Parameters.AddWithValue("@ID", pdf.ContentLink.ID);

                                cmd.ExecuteNonQuery();
                                i++;
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        output.AppendLine(string.Format("ID: {0}, Error: {1}",
                        pdf.ContentLink.ID,
                        ex.Message));
                    }
                }
            }

            return string.Format(
                "Fixed {0} pdfs. \n Errors:\n{1}", 
                i, 
                output);
        }
    }
#201569
Feb 22, 2019 13:42
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.