Monday, March 28, 2016

Where my block has been used on server? A question that all back-end developer have in mind



The story started when I had a task to remove old blocks that we don't use any more. From a back-ender's point of view, I just needed to find all references in my code and make sure that it has not been used anywhere. But of course it is not correct when dealing with a CMS like EpiServer since they can be used in a ContentArea.

Yes, I know, we have also [AllowedType] attribute that we use in order to limit contentAreas, but still, there can be some items in blocks tree that has not been used in any page and may cause a problem if an editor click on them.

So what shall we do?

First, Every content in EpiServer will be saved in tblContent. if you want to make sure that there is no instance from your typename it is enough to check that table.Code:
SELECT c.*   FROM [dbo].[tblContent] c
inner join [dbo].[tblContentType] ct on c.fkContentTypeID = ct.pkID
where  [ModelType] like '%TypeName%'

But it is only 10% of the cases, besides where is the fun?!!!
I want to know how many instances of my type exists and where are they now? also I want to know how to find their parent in the tree. So I wrote this code:

Code:
declare @TypeName nvarchar(50)
set @TypeName = 'myBlockType'

select tbl2.contentName as contentName, tbl2.contentSegment as ContentSegment, tbl2.ContentGUID as ContentGUID,
con2pkID ContainerID,con2ContentGUID ContainerGUID, conLang.name as ContainerName,conLang.URLSegment as ContainerURLSegment, contype.Name as ContainerTypeName, 
contype.ModelType as ContainerModelType, con2.fkParentID as ContainersParentId, conContainerParentLanguage.Name as ContainerParentName, conContainerParentType.Name as ContainerParentName

from [dbo].[tblContentProperty] cp  
 inner join 
(SELECT  c.*, cl.name as contentName,  cl.URLSegment as contentSegment FROM [dbo].[tblContent] c
inner join [dbo].[tblContentType] ct on c.fkContentTypeID = ctpkID
inner join tblContentLanguage cL on cL.fkContentID = c.pkID
where  ct.Name like @TypeName)  tbl2 on cp.LongString like '%'+cast( tbl2.ContentGUID as nvarchar(50))+'%'
inner join tblContent con2 on con2.pkID = cp.fkContentID
inner join [dbo].[tblContentType] contype on con2.fkContentTypeID = contypepkID
inner join tblContentLanguage conLang on conLang.fkContentID = con2pkID
inner join tblContent conContainerParent on conContainerParent.pkID = con2fkParentID
inner join tblContentType conContainerParentType on conContainerParent.fkContentTypeID = conContainerParentTypepkID
inner join tblContentLanguage conContainerParentLanguage on conContainerParentLanguage.fkContentID = con2.fkParentID

This code will show you all instances of a type, and where they have been contained including typename and the address that we can find the parent in the tree.


The result will be something like this



But wait a minute! what if I can't find the container it self?!
Well, that is easy :)  the query is 90% the same, but we just need to search for the contentId (instance) instead of the type name.
Of course if you search for the containers type name, you will eventually find it, But it is easier to change 2 lines of code :)

Code:
declare @ContentGUID nvarchar(50)
set @ContentGUID = 'B6845FFC-5475-4FC3-C701-5A5D6FD5F967' -- put you content GUID in here 

select tbl2.contentName as contentName, tbl2.contentSegment as ContentSegment, tbl2.ContentGUID as ContentGUID,
con2pkID ContainerID,con2ContentGUID ContainerGUID, conLang.name as ContainerName,conLang.URLSegment as ContainerURLSegment, contype.Name as ContainerTypeName, 
contype.ModelType as ContainerModelType, con2.fkParentID as ContainersParentId, conContainerParentLanguage.Name as ContainerParentName, conContainerParentType.Name as ContainerParentName

from [dbo].[tblContentProperty] cp
 inner join
(SELECT  c.*, cl.name as contentName,  cl.URLSegment as contentSegment
FROM [dbo].[tblContent] c
inner join tblContentLanguage cL on cL.fkContentID = c.pkID
where c.ContentGUID like @ContentGUID)  tbl2 on cp.LongString like '%'+cast( tbl2.ContentGUID as nvarchar(50))+'%'
inner join tblContent con2 on con2.pkID = cp.fkContentID
inner join [dbo].[tblContentType] contype on con2.fkContentTypeID = contypepkID
inner join tblContentLanguage conLang on conLang.fkContentID = con2pkID
inner join tblContent conContainerParent on conContainerParent.pkID = con2fkParentID
inner join tblContentType conContainerParentType on conContainerParent.fkContentTypeID = conContainerParentTypepkID
inner join tblContentLanguage conContainerParentLanguage on conContainerParentLanguage.fkContentID = con2.fkParentID

9 comments:

  1. Nice tool! But instead of making queries to the database, I think it's better to use Episerver's API as the database structure might change in the future without specific notice.

    Have a look at my blog post to check how you find usages of content with Episerver's API

    http://talk.alfnilsson.se/2013/06/05/find-pages-containing-a-certain-content-in-a-contentarea/

    ReplyDelete
    Replies
    1. Hi Alf,

      First, thanks for comment. If you need to show this data to a customer, or even admin, yes I will write a service and use it in my page.
      In my scenario, which is for developers, I didn't want to add a page/service to the solution. I just needed to know where is my content :) and I think it is common for most people.

      Delete
    2. Hi,

      In my blog post I'm referring to already existing Services in the Episerver API. Even if you're creating tools for developers it's a better practice to use the API rather than going to the database.

      Delete
    3. Dude, I'm not creating tools.
      It is the same as running any other SQL command on your production server. If you know why you need them, you will understand why someone would need this command, otherwise, I cannot help you with it.

      Delete
    4. As it is something reusable and for a developer would use, I would refer it as "tool". We might have different wordings on that.

      I don't mean to be rude or bashing your idea, I'm just suggesting that if you can accomplish something using the built in API it's referable as the API might cover information that is not in the data structure (database), or if Episerver will change the database structure.
      Then you don't need to rewrite as much when the database change.

      Again, it's a nice concept, just giving hints how you can improve it and make it less dependent on the SQL structure of the current Episerver version.

      Episerver has and will change database structure without releasing a new major version, while breaking changes in the API requires increasing the major version.

      Delete
  2. This comment has been removed by the author.

    ReplyDelete
  3. Thanks, helped a lot today :) Will create a plugin for the future needs.

    ReplyDelete
    Replies
    1. Cool! :) I'm happy that it helped you ;)

      Delete
  4. replica Soccer Jerseys, combining elegant style and cutting-edge technology, a variety of styles of replica fc dallas Jerseys, the pointer walks between your exclusive taste style.

    ReplyDelete