MVC and generated pages

lawrence whittemore asked on January 13, 2020 21:53

I'm working through learning MVC and am starting off by building a basic site. I'm new to MVC and the development side of kentico in general.

Its starting to click, which is great, but I still have a ton of questions. One thing I am working on right now is just setting up a detail page.

I added this to my viewmodel page

public static DocumentQuery<Story> GetStory(int id)
    {
        return GetStories().WhereEquals("StoryID", id);
    }

and it works but it returns an Enumerable with just 1 item in it. I am getting this error, because in my view i don't want an enumerable.

The model item passed into the dictionary is of type 'System.Linq.EnumerableQuery`1[NLHAR2019.Models.StoryViewModel]', but this dictionary requires a model item of type 'NLHAR2019.Models.StoryViewModel'.

How would I change my code to have it return just the 1 item I am looking for without it being enumerable. "GetStories" is part of the code that was generated by kentico in the StoryProvider class I generated from the page type.

Hope this makes sense.

Recent Answers


lawrence whittemore answered on January 13, 2020 22:24

So.. I made something work... probably the wrong way to go about it. public class StoryViewModel : StoryProvider { public int StoryID { get; set; } public string Title { get; set; } public string BGColor { get; set; } public string Summary { get; set; } public string VideoId { get; set; } public string Description { get; set; } public string Image { get; set; } public string AniProp { get; set; }

    //Node Items, not part of the page type
    public Guid NodeGUID { get; set; }
    public string NodeAlias { get; set; }


    // Modified from StoryProvider to use StoryID vs NodeId or a GUID
    //By Lawrence
    public static DocumentQuery<Story> GetStory(int id)
    {
        return GetStories().WhereEquals("StoryID", id);
    }

}
public class SingleStoryViewModel : StoryViewModel
{
    public SingleStoryViewModel(Story detailPage)
    {
        StoryID = detailPage.StoryID;
        Title = detailPage.Title;
        BGColor = detailPage.BGColor;
        Summary = detailPage.Summary;
        VideoId = detailPage.VideoId;
        Description = detailPage.Description;
        Image = detailPage.Image;
        AniProp = detailPage.AniProp;

    }
}

On my controller I have this

 // GET: Looking to get 1 items details
    public ActionResult Details(int id)
    {

        //Moved to Model to prevent overwright in generated code
        Story story = StoryViewModel.GetStory(id)
            .Columns("StoryID", "Title", "BGColor", "Summary", "VideoId", "Description", "Image", "AniProp")
            .OrderBy("NodeOrder");           

        var model = new SingleStoryViewModel(story);            

        return View(model);
    }

seems to work.. I just don't fully understand why one returns and enumerable and the other doesn't

0 votesVote for this answer Mark as a Correct answer

Sean Wright answered on January 14, 2020 04:17 (last edited on January 14, 2020 04:26)

Lawrence,

You want to use the following

Story story = StoryProvider
    .GetStory(id)
    .Columns("StoryID", "Title", "BGColor", "Summary", "VideoId", "Description", "Image", "AniProp")
    .OrderBy("NodeOrder")
    .TopN(1)
    .TypedResult // This is Kentico method
    .FirstOrDefault(); // This is a System.Linq method

All of the auto-generated classes for each Page Type you create will work with DocumentQuery<T> where T is your custom Page Type.

You can learn more about how to use DocumentQuery<T> in the documentation

https://docs.kentico.com/k12sp/custom-development/working-with-pages-in-the-api

https://docs.kentico.com/k12sp/custom-development/working-with-pages-in-the-api/reference-documentquery-methods

There are a lot of methods and not all of them are in the documentation, but here are a couple of blog posts that might help:

https://carly.io/2016/10/05/kentico-9-data-query-api-examples/

https://dev.to/seangwright/kentico-12-design-patterns-part-14-documentquery-and-objectquery-tips-2c7h (shameless plug for my own blog)

The DocumentQuery<T> data access pattern was added to Kentico back in Kentico 8. Here is a post about it when it was first released that might also be helpful:

https://devnet.kentico.com/articles/kentico-8-technology-documentquery-api

In the code snippet I provided above you can see I used a combination of Kentico's querying methods and System.Linq. There is also a .FirstObject property that can be found when working with DocumentQuery<T>, but it has been deprecated and using .FirstOrDefault(); is the recommended approach.

You can see I used .TopN(1) as well. This isn't required, but it is a good practice to use this method when you want only 1 result. .FirstOrDefault(); gives you the first object of the collection in memory, whereas .TopN(1) ensures only 1 result is brought back from the database to memory.

1 votesVote for this answer Mark as a Correct answer

Trevor Fayas answered on January 14, 2020 18:03 (last edited on January 14, 2020 18:05)

Don't forget Culture and current version!

Here's a good example of using MVCCaching module (auto handles caching for ya), and autofac the culture and current version, and how to generate your "GetThePageByID(int ID)" thing

https://github.com/KenticoDevTrev/MVCCaching/blob/master/MVCCaching.Kentico.Examples/Repositories/Implementations/KenticoExamplePageTypeRepository.cs

/// <summary>
    /// No Cache 'needed' however basic detection of it will simply put the "nodes|sitename|classname|all", so i'm adding one
    /// </summary>
    /// <param name="ID">The NodeID</param>
    /// <returns>The Page</returns>
    [CacheDependency("nodeid|{0}")]
    public ExamplePageType GetExamplePage_TreeNode(int ID)
    {
        return ExamplePageTypeProvider.GetExamplePageType(ID, mCultureName, SiteContext.CurrentSiteName)
            .LatestVersion(mLatestVersionEnabled)
            .Published(!mLatestVersionEnabled)
            .CombineWithDefaultCulture()
            .FirstOrDefault();
    }
0 votesVote for this answer Mark as a Correct answer

   Please, sign in to be able to submit a new answer.