November Happy Hour will be moved to Thursday December 5th.
November Happy Hour will be moved to Thursday December 5th.
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.
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?
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
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);
}
}
Having to look at a similar issues to this, we have a site where previously we had only MediaFile and now we need to split out PDFs from that into PdfFile (which will still inherit from MediaFile).
Trying to figure out where we'd need to make updates in the database, as we specifically need to target MediaFile which are PDFs only and not all of them. And unfortunately there are some custom prioperties which, despite inheriting from MediaFile, end up needing to be remapped in the database.
I'm thinking best bet at this point may be reverse engineering the netConvert... stored procedures into varients which allow us to just target specific items rather than types as a whole. Am I right in thinking these are the stored procedurers used by the current page type conversion in the UI?
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