More in this section

Forums / Developing with Sitefinity / On IManager GetItem/GetItemOrDefault throw exception when item does not exist.

On IManager GetItem/GetItemOrDefault throw exception when item does not exist.

7 posts, 0 answered
  1. Erik
    Erik avatar
    62 posts
    Registered:
    02 May 2011
    08 Feb 2013
    Link to this post

    This is an error related to the solution on this page: http://www.sitefinity.com/developer-network/forums/developing-with-sitefinity-/get-tags-from-pagecontrols

    I have an implementation of IManager. In this case I get it by calling DynamicModuleManager.GetManager(). If I call GetItem and the item has been deleted then it throws the following error:

    [NullReferenceException: Object reference not set to an instance of an object.]
    DynamicModule.ns.Wrapped_OpenAccessDynamicModuleProvider_8757eda9740b460eab5ca64f3e106cb1.GetItem(Type itemType, Guid id) +322
    Telerik.Sitefinity.Data.ManagerBase`1.GetItem(Type itemType, Guid id) +96

    I found this odd as I would expect a function that retrieves an item to return NULL if it could not find it, or at least a relevant error. Then I ran across GetItemOrDefault and figured that it would return the default for the type (NULL) if it couldn't find it. Instead it throws a different error:

    [ArgumentException: Invalid data item type "Telerik.Sitefinity.DynamicModules.Model.DynamicContent". Accepted item types are: "Telerik.Sitefinity.DynamicModules.Model.DynamicContent".]
    DynamicModule.ns.Wrapped_OpenAccessDynamicModuleProvider_70eb871433ea455abe06db6a5ded8ba2.GetItemOrDefault(Type itemType, Guid id) +322
    Telerik.Sitefinity.Data.ManagerBase`1.GetItemOrDefault(Type itemType, Guid id) +96

    I found the error rather confusing since the data item type is identical to the supposed accepted item type. So my question is: How can I figure out if an item exists before I call GetItem on an implementation of IManager?

    Thanks!


  2. Stephen2
    Stephen2 avatar
    94 posts
    Registered:
    05 Feb 2012
    09 Feb 2013 in reply to Erik
    Link to this post

    Just freehand, here's my method - let's use pages as an example:

    var item = PageManager.GetManager().GetPageNodes().SingleOrDefault(o => o.Id == MyGuid);

    And if it's content,  usually make sure it's published:

    var image = LibrariesManager().GetManager().GetImages().SingleOrDefault(o => o.Id == MyGuid && o.Visible && o.Status = ContentLifecycleStatus.Live);

  3. Erik
    Erik avatar
    62 posts
    Registered:
    02 May 2011
    11 Feb 2013
    Link to this post

    Hi Stephen,

    Thanks for the suggestion. Do you know if the SingleOrDefault uses Linq-to-Entities/SQL or Linq-to-Objects? I wouldn't want to be returning all images or all pages from a sql statement and then sifting through the responses in memory rather than getting just the record I want as the result of a sql statement. Since the "GetItems" call off of the IManager interface returns an IEnumerable rather than an IQueryable I suspect that SingleOrDefault is using Linq-to-Objects at that point (ref: http://msdn.microsoft.com/en-us/library/bb397919.aspx). I wouldn't know how to setup EFTrace for Sitefinity to check. Do you know?

    Based on that assumption, it seems that my best bet is to wrap my "GetItem" calls in a try/catch and return Default(T) on error.

  4. Stephen2
    Stephen2 avatar
    94 posts
    Registered:
    05 Feb 2012
    11 Feb 2013 in reply to Erik
    Link to this post

    No probs... I'm not a guru of this by any means, but I just ran a SQL trace using the 2nd snippet - GetImages() which seemed to execute two queries: (I've cut out the sp_prepexec stuff and replaced paramaterised variables with their values:

    SELECT COUNT(1) FROM ( SELECT a.[content_id] AS COL1, a.[voa_class] AS COL2, ... AS COL40 FROM [sf_libraries] a WHERE a.[app_name] = '/Libraries') AS TMP_COUNT

    This returns "19" for my test database... Suggesting 19 images in my database I think.  Suspect if the above query returns zero, then you get a null return.

    Next, seeing as the above was fine, it ran:

    SELECT  TOP(2) a.[content_id] AS COL1, a.[voa_class] AS COL2, ... AS COL49
    FROM [sf_media_content] a
    WHERE a.[app_name] = '/Libraries'
    AND a.[content_id] = '74DB6EA1-70A8-4A5D-904B-2FE64791F985'
    AND a.[visible] <> 0
    AND a.[status] = 2
    AND a.[voa_class] = 1053642113

    Note the TOP(2) clause, meaning the return from SQL is limited.  Suggest then that if two were returned by the query that the code throws the "more than one object" exception.

    I just used SQL server profiler, capturing data into a table so I could query it to gather this information - oh.. SF Version 5.3.3900, SQL 2008R2

    Suggest that this sounds less expensive than catching an exception, though I don't know for sure.. It feels more "clean" anyway.

  5. Erik
    Erik avatar
    62 posts
    Registered:
    02 May 2011
    11 Feb 2013
    Link to this post

    Thanks for the information. I am surprised that it works that way. I find it odd that it does a TOP(2). I would have expected a TOP(1).

  6. Stephen2
    Stephen2 avatar
    94 posts
    Registered:
    05 Feb 2012
    11 Feb 2013 in reply to Erik
    Link to this post

    "SingleOrDefault" will throw an exception if >1 return.  If the SQL query was limited to 1 result only, C# would have no way of knowing if >1 was returned - hence the TOP(2)

     

  7. Erik
    Erik avatar
    62 posts
    Registered:
    02 May 2011
    11 Feb 2013
    Link to this post

    Ah, makes sense.

7 posts, 0 answered