I'm trying to make a razor macro which renders X focus products on the frontpage. However, if the admin haven't set any products as focusproduct, it should just render three random products, downscaling to: if administrator has selected one or two products as focusproducts, it should thus render two or a single product(s)
My razor file looks like this:
@* This macro renders the focus products on the frontpage *@
@using UCommerce.EntitiesV2
@using UCommerce.Extensions
@using UCommerce.Api
@{
// Get focus products
var focusProducts = new List<Product>();
var allProducts = Product.All().Where(x => x.DisplayOnSite);
int takeCount = 3;
<ul class="thumbnails focus-products">
@* Get all focus products *@
@foreach(var product in allProducts)
{
if(product.DisplayOnSite && product.GetProperty("Fokusprodukt") != null && Convert.ToBoolean(product.GetProperty("Fokusprodukt").GetValue()))
{
focusProducts.Add(product);
}
}
@* Check if there was any focus products *@
@if(focusProducts.Count > 0)
{
// Render focus products
@RenderFocusProducts(focusProducts)
// Check if the number of focus products are less than three
if(focusProducts.Count < 3)
{
// Calculate new take count to render rest of the focus products as random products
takeCount = takeCount - focusProducts.Count;
// Render the rest as random products so there's always three products on the frontpage
@RenderRandomProducts(takeCount, allProducts, focusProducts)
}
}
else
{
// No focus products found. Render three random products
@RenderRandomProducts(takeCount, allProducts, focusProducts)
}
</ul>
}
@helper RenderFocusProducts(List<Product> products)
{
foreach (var product in products)
{
<li class="span4">
<a href="@CatalogLibrary.GetNiceUrlForProduct(product)">
<div class="thumbnail">
<div class="image"><img src="@Model.MediaById(product.PrimaryImageMediaId).umbracoFile" alt=""></div>
<h3>@product.Name</h3>
<p>
@product.GetProperty("Teaser").GetValue()
</p>
</div>
</a>
</li>
}
}
@helper RenderRandomProducts(int takeCount, IQueryable<Product> products, List<Product> focusProducts)
{
// Pick three random products which are not marked as focus products
var rnd = new Random();
var randomProducts = products.ToList().OrderBy(x => rnd.Next()).Where(x => !focusProducts.Contains(x)).Take(takeCount);
foreach (var product in randomProducts)
{
<li class="span4">
<a href="@CatalogLibrary.GetNiceUrlForProduct(product)">
<div class="thumbnail">
<div class="image"><img src="@Model.MediaById(product.PrimaryImageMediaId).umbracoFile" alt=""></div>
<h3>@product.Name</h3>
<p>
@product.GetProperty("Teaser").GetValue()
</p>
</div>
</a>
</li>
}
}
What I'm concerned about here is performance, since I basically start by pulling all the products from the database to find the products marked with "Fokusprodukt" (Focusproduct) and work my way from there.
Was wondering if there was a more performant method than this I may have missed? :-)
I would use a category to hold the focus product (make a new category definitions and filter it from the navigation and other places where you would display categories).
It would also be easier to maintain when you have a list of products in the backend and it should perform a lot better.
So something like:
var focusCategory = Category.FirstOrDefault(x => x.Definition.Name == "XXX");
What you want to do is make sure that you leave the work of selecting randon products to the database.
Doing it as pure SQL looks like this:
SELECT productId FROM uCommerce_Product ORDER BY NEWID()
The trick then become to do the same via the uCommerce query API.
You can to go a little deep in the query API and use HQL to get the best performance:
IList<Product> randomProducts; var sessionProvider = ObjectFactory.Instance.Resolve<ISessionProvider>(); using (var session in sessionProvider.GetSession()) { randomProducts = session .CreateQuery("FROM Product p WHERE p.ParentProduct IS NULL ORDER BY NEWID()") // random ordering with NEWID()
.SetMaxResults(3) // Limit to three products
.List<Product>(); // Execute the query }
Not too bad :)
I took the liberty to only ask for products and product families filtering variants from the result.
Product rendering and performance ponderings
Hi all,
I'm trying to make a razor macro which renders X focus products on the frontpage. However, if the admin haven't set any products as focusproduct, it should just render three random products, downscaling to: if administrator has selected one or two products as focusproducts, it should thus render two or a single product(s)
My razor file looks like this:
What I'm concerned about here is performance, since I basically start by pulling all the products from the database to find the products marked with "Fokusprodukt" (Focusproduct) and work my way from there.
Was wondering if there was a more performant method than this I may have missed? :-)
Thanks a lot in advance.
All the best,
Bo
I would use a category to hold the focus product (make a new category definitions and filter it from the navigation and other places where you would display categories).
It would also be easier to maintain when you have a list of products in the backend and it should perform a lot better.
So something like:
Hi Bo,
What you want to do is make sure that you leave the work of selecting randon products to the database.
Doing it as pure SQL looks like this:
The trick then become to do the same via the uCommerce query API.
You can to go a little deep in the query API and use HQL to get the best performance:
Not too bad :)
I took the liberty to only ask for products and product families filtering variants from the result.
Hope this helps.
Nikolaj: Thanks a lot! Good solution, but the customer didn't want to maintain a separate category for the focus products :-/
Søren: Fantastic! That's exactly what I was looking for :-) Thanks so much.
is working on a reply...
This forum is in read-only mode while we transition to the new forum.
You can continue this topic on the new forum by tapping the "Continue discussion" link below.