How I can use predicate buider for Sitecore Lucene Search - sitecore

I am working on Sitecore 8.1 and I am implementing filter functionality for one of the page by Sitecore lucene. Fot filtering I am using predicate builder. I have 3 multi-lists field on detail items
Product
Category
Services
Now on listing page I have all three group filters as checkboxes as given in below image -
My Requirement is I want to apply Or between inside the group like between products condition should be Or and between two groups condition should be And. For example products and Category should be And.
I followed http://getfishtank.ca/blog/building-dynamic-content-search-linq-queries-in-sitecore-7 blog post to implement this
To achieve this what I am trying -
var builder = PredicateBuilder.True<TestResultItem>();
var Categorybuilder = PredicateBuilder.False<TestResultItem>();
if (!string.IsNullOrEmpty(Categorys))
{
var CategoryItems = Categorys.Split('|');
foreach (var Category in CategoryItems)
{
var ct = Sitecore.ContentSearch.Utilities.IdHelper.NormalizeGuid(Categorys, true);
Categorybuilder = Categorybuilder.Or(i => i.Category.Contains(ct));
}
}
var Servicebuilder = PredicateBuilder.False<TestResultItem>();
if (!string.IsNullOrEmpty(Service))
{
var ServiceItems = Service.Split('|');
foreach (var ser in ServiceItems)
{
var si = Sitecore.ContentSearch.Utilities.IdHelper.NormalizeGuid(ser, true);
Servicebuilder = Servicebuilder.Or(i => i.Service.Contains(si));
}
}
var productsbuilder = PredicateBuilder.False<TestResultItem>();
if (!string.IsNullOrEmpty(products))
{
var productItems = products.Split('|');
foreach (var product in productItems)
{
var pd = Sitecore.ContentSearch.Utilities.IdHelper.NormalizeGuid(product, true);
productsbuilder = productsbuilder.Or(i => i.Category.Contains(pd));
}
}
Servicebuilder = Servicebuilder.Or(Categorybuilder);
productsbuilder = productsbuilder.Or(Servicebuilder);
builder = builder.And(productsbuilder);
The above given code is not working for me. I know I am doing something wrong as I am not good with Predicate builder, Or condition is not working between check boxes group.
Can anyone please tell me where I am wrong in given code or any best way to achieve this.
Any help would be appreciated

I did something similar recently and it works like this:
Create your "or" predicates:
var tagPredicate = PredicateBuilder.False<BlogItem>();
tagPredicate = tagValues.Aggregate(tagPredicate, (current, tag) => current.Or(p => p.Tags.Contains(tag)))
where tagValues is an IEnumerable containing the normalized guids.
I do this for several guid lists. In the end I wrap them together like this:
var predicate = PredicateBuilder.True<BlogItem>();
predicate = predicate.And(tagPredicate);
predicate = predicate.And(...);
Looking at your code: first of all change
Servicebuilder = Servicebuilder.Or(Categorybuilder);
productsbuilder = productsbuilder.Or(Servicebuilder);
builder = builder.And(productsbuilder);
into
builder = builder.And(Categorybuilder);
builder = builder.And(Servicebuilder);
builder = builder.And(productsbuilder);

You need to have one main predicate to join filters with AND condition & other predicates (e.g. for categories or services or products) to join filters internally with OR condition.
// This is your main predicate builder
var builder = PredicateBuilder.True<TestResultItem>();
var Categorybuilder = PredicateBuilder.False<TestResultItem>();
var Servicebuilder = PredicateBuilder.False<TestResultItem>();
var productsbuilder = PredicateBuilder.False<TestResultItem>();
builder = builder.And(Categorybuilder);
builder = builder.And(Servicebuilder);
builder = builder.And(productsbuilder);
Hope this will help you.

Thanks all for providing your inputs -
I updated the code as per your inputs and now it's working.
There was two changes in my old code one was builder for multilist should be inside the if statement and also adding newly created builder to main builder on same location (inside the if statement) -
I am sharing the code below so that if anyone want to use it he can easily copy from here -
var builder = PredicateBuilder.True<TestResultItem>();
if (!string.IsNullOrEmpty(Categorys))
{ var Categorybuilder = PredicateBuilder.False<TestResultItem>();
var CategoryItems = Categorys.Split('|');
foreach (var Category in CategoryItems)
{
var ct = Sitecore.ContentSearch.Utilities.IdHelper.NormalizeGuid(Categorys, true);
Categorybuilder = Categorybuilder.Or(i => i.Category.Contains(ct));
}
builder = builder.And(Categorybuilder);
}
if (!string.IsNullOrEmpty(Service))
{
var Servicebuilder = PredicateBuilder.False<TestResultItem>();
var ServiceItems = Service.Split('|');
foreach (var ser in ServiceItems)
{
var si = Sitecore.ContentSearch.Utilities.IdHelper.NormalizeGuid(ser, true);
Servicebuilder = Servicebuilder.Or(i => i.Service.Contains(si));
}
builder = builder.And(Servicebuilder);
}
if (!string.IsNullOrEmpty(products))
{
var productsbuilder = PredicateBuilder.False<TestResultItem>();
var productItems = products.Split('|');
foreach (var product in productItems)
{
var pd = Sitecore.ContentSearch.Utilities.IdHelper.NormalizeGuid(product, true);
productsbuilder = productsbuilder.Or(i => i.Category.Contains(pd));
}
builder = builder.And(productsbuilder);
}
In the above code Categorys, Service and products are pipe separated values which are coming from Sitecore Multi-list field.
Thanks again everyone for help!!

Related

SharePoint WebsInfo Description is always Null

I'm trying to get the Description of a Site but it's always null in WebsInfo! Can someone please help me understand this? I also tried using OpenWeb but that was messing up the URL that I passed in.
var site = new SPSite(currentWeb.Url);
string url = currentWeb.Url + #"/" + siteName;
var webObject = site.AllWebs;
foreach (var web in webObject.WebsInfo)
{
siteDescription = web.Description;
}
I guess there is a bug in the WebsInfo that has never been resolved!! I ended up using SPWebCollection.
//This will find the current URL and iterate through it's site Collection
var oSiteCollection = new SPSite(SPContext.Current.Web.Url);
//Gets all webs meaning sub webs and their webs.
var collWebsites = oSiteCollection.AllWebs;
foreach (SPWeb web in collWebsites)
{
if (web.ServerRelativeUrl.StartsWith(kpi.BusinessUnitUrl))
{
kpi.BusinessUnitDescription = web.Description;
kpi.SiteSpecificAreaDescription = web.Description;
var collLists = web.Lists;
IterateLists(collLists, false, ref kpi);
}
}

Using GP Web Service: How do I delete a SalesOrderLine from a SalesOrder?

Can someone help me delete a SalesOrderLine from a SalesOrder?
I'm using the GP WS Native Endpoint
My code executes without an error.
However, after updating the SalesOrder, the line I removed still remains.
var salesDocumentKeyObject = new SalesDocumentKey {Id = salesDocumentKey, CompanyKey = this.CompanyKey};
var salesOrder = this.DynamicsGpClient.GetSalesOrderByKey(salesDocumentKeyObject, this.Context);
var newLines = salesOrder.Lines.Where(l => l.Key.LineSequenceNumber != lineItemSequence).ToArray();
salesOrder.Lines = newLines;
var salesOrderUpdatePolicy = this.DynamicsGpClient.GetPolicyByOperation("UpdateSalesOrder", this.Context);
this.DynamicsGpClient.UpdateSalesOrder(salesOrder, this.Context, salesOrderUpdatePolicy);
Thank you for any help,
Karl
Microsoft Dynamics GP Web Service has poor documentation and examples.
Do delete a sales order line, you retrieve the order, locate the line to delete and set the sales order line property, DeleteOnUpdate to true, and then save the order.
Updated code below:
var salesDocumentKeyObject = new SalesDocumentKey {Id = salesDocumentKey, CompanyKey = this.CompanyKey};
var salesOrder = this.DynamicsGpClient.GetSalesOrderByKey(salesDocumentKeyObject, this.Context);
var target= salesOrder.Lines.FirstOrDefault(l => l.Key.LineSequenceNumber == lineItemSequence);
if (target != null) {
target.DeleteOnUpdate = true;
}
var salesOrderUpdatePolicy = this.DynamicsGpClient.GetPolicyByOperation("UpdateSalesOrder", this.Context);
this.DynamicsGpClient.UpdateSalesOrder(salesOrder, this.Context, salesOrderUpdatePolicy);

How to use boosting in solrnet while using default query?

I am using SolrNet to do query on my default search field and not on any specific field. How can I use Boost on a specific field in that case? Below is the code snippet.
List filter = BuildQuerySingleLine(arrParams);
var customer = solr.Query(parameters.SingleLineSearch, new QueryOptions
{
FilterQueries = filter,
SpellCheck = new SpellCheckingParameters { Collate = true },
OrderBy = new[] { new SortOrder("score", Order.DESC), SortOrder.Parse("score DESC") },
StartOrCursor = new StartOrCursor.Start(parameters.StartIndex),
Rows = parameters.NumberOfRows
});
At last I found the solution to this problem. For this I have used dismax request handler and passed the qf param value through SOLRNET.
With this you can pass the dynamic boost value to the SOLR query, on different fields.
var extraParams = new Dictionary<string, string> { { "qt", "dismax" }, { "qf", "fieldName^1 FieldName^0.6" } };
var customer = solr.Query(parameters.SingleLineSearch, new QueryOptions
{
StartOrCursor = new StartOrCursor.Start(parameters.StartIndex),
Rows = parameters.NumberOfRows,
},
ExtraParams = extraParams
});
According to this document: Querying and The DisMax Query Parser
var extraParams = new List<KeyValuePair<string, string>>();
extraParams.Add(new KeyValuePair<string, string>("bq", "SomeQuery^10"));
extraParams.Add(new KeyValuePair<string, string>("bq", "SomeOtherQuery^10"));
var options new new QueryOptions();
options.ExtraParams = extraParams; //Since my List implements the right interface
solr.Query(myQuery, options)
the bq parameter should be used to boost the Query. #Abhijit Guha has an excellent answer, to use the same idea on the Field: qf (Query fields with optional boosts)
QueryOptions options = new QueryOptions
{
ExtraParams = new KeyValuePair<string, string>[]
{
new KeyValuePair<string,string>("qt", "dismax"),
new KeyValuePair<string,string>("qf", "title^1")
},
Rows = 10,
Start = 0
};
Thank You!

Caml Query returning null

I was trying to retrieve documents from document library using CAML Query, but this query returns null. Please help to solve this.
SPDocumentLibrary oDocumentLibrary = (SPDocumentLibrary)oWebsite.Lists["SampleDocument"];
SPQuery query = new SPQuery();
query.Query = string.Format("<Where><Eq><FieldRef Name='Author' /><Value Type='Text'>Name</Value></Eq></Where>");
SPListItemCollection collListItems = oDocumentLibrary.GetItems(query);
DataTable dt = collListItems.GetDataTable();
You can check Caml query in Caml Designer if the query is returning exact result or not.
Try with Camlex add CamlexNET using Nuget
using CamlexNET;
var caml = Camlex.Query().Where(x => ((string)x["Author"] == "Value").ToString();
var query = new SPQuery
{
Query = caml,
RowLimit = 5000
};
SPList list = web.Lists["Document"];
SPListItemCollection items = list.GetItems(query);
foreach (SPListItem itm in items)
{
//var id = Convert.ToString(itm["ID"]);
}

How to retrieve a total result count from the Sitecore 7 LINQ ContentSearch API?

In Lucene.Net, it is possible to retrieve the total number of matched documents using the TopDocs.TotalHits property.
This functionality was exposed in the Advanced Database Crawler API using an out parameter in the QueryRunner class.
What is the recommended way to retrieve the total result count using Sitecore 7's new LINQ API? It does not seem possible without enumerating the entire result set. Here is what I have so far:
var index = ContentSearchManager.GetIndex("sitecore_web_index");
using (var context = index.CreateSearchContext())
{
var query = context.GetQueryable<SearchResultItem>()
.Where(item => item.Content == "banana");
var totalResults = query.Count(); // Enumeration
var topTenResults = query.Take(10); // Enumeration again? this can't be right?
...
}
Try this:
using Sitecore.ContentSearch.Linq; // GetResults on IQueryable
var index = ContentSearchManager.GetIndex("sitecore_web_index");
using (var context = index.CreateSearchContext())
{
var query = context.GetQueryable<SearchResultItem>()
.Where(item => item.Content == "banana");
var results = query.GetResults();
var totalResults = results.TotalSearchResults;
var topTenResults = results.Hits.Take(10);
...
}
To get more info about sitecore and linq you can watch this session and look at this repo.