Query library items by tag
Hi all,
I want to query some items from an image library.
I have this code:
var images = App.WorkWith().Images().Where((w) => w.Album.Title ==
"Visuals"
&&
w.Status == Telerik.Sitefinity.GenericContent.Model.ContentLifecycleStatus.Live).Get();
List<Telerik.Sitefinity.Libraries.Model.Image> filteredImages =
new
List<Telerik.Sitefinity.Libraries.Model.Image>();
foreach
(Telerik.Sitefinity.Libraries.Model.Image item
in
images)
ContentItem i = item
as
ContentItem;
if
(i.TagsText.IndexOf(
"Visual"
) > -1)
filteredImages.Add(item);
Hi Daniel,
Please take a look at this post.
Regards,
Ivan Dimitrov
the Telerik team
Hi Ivan,
Thanks for the help.
I don't know the GUID of the Taxon.
I have to do it by name/title.
Regards,
Daniel
Hello Daniel,
Use TaxonomyManager to get the taxon and then its ID.
Best wishes,
Ivan Dimitrov
the Telerik team
Thanks that worked.
Here is the completed code for convenience:
public
partial
class
Test : System.Web.UI.Page
protected
void
Page_Load(
object
sender, EventArgs e)
var taxonomyManager = TaxonomyManager.GetManager();
var taxon = taxonomyManager.GetTaxa<FlatTaxon>().Where(t => t.Name ==
"tag1"
).Single();
string
itemTypeName =
"Telerik.Sitefinity.Libraries.Model.Image"
;
Type itemType = TypeResolutionService.ResolveType(itemTypeName);
var manager = ManagerBase.GetMappedManager(itemType,
""
);
ContentDataProviderBase contentProvider = manager.Provider
as
ContentDataProviderBase;
var items = GetItems(taxon, contentProvider, itemType);
foreach
(Telerik.Sitefinity.Libraries.Model.Image item
in
items)
Response.Write(
"ID: "
+ item.Id +
"<br />"
);
Response.Write(
"Url Name: "
+ item.UrlName +
"<br />"
);
private
IEnumerable GetItems(ITaxon taxon, ContentDataProviderBase contentProvider, Type itemType)
TaxonomyPropertyDescriptor prop = GetPropertyDescriptor(itemType, taxon);
int
? totalCount = 0;
var filter =
"Status = Master"
;
var items = contentProvider.GetItemsByTaxon(taxon.Id, prop.MetaField.IsSingleTaxon, prop.Name, itemType, filter,
string
.Empty, 0, 100,
ref
totalCount);
return
items;
private
TaxonomyPropertyDescriptor GetPropertyDescriptor(Type itemType, ITaxon taxon)
return
TaxonomyManager.GetPropertyDescriptor(itemType, taxon);
Hello Basem,
There is a way through the fluent API, but again you should know the category/tag ID
var categID =
new
Guid(
""
);
var content = App.WorkWith().NewsItems().Where(ci => ((IList<Guid>)ci.GetValue(
"Category"
)).Contains(categID));
Hello,
Does there exist a best practice for getting items by more than one Taxon. I'm filtering NewsItems by Category and Tag. I've been able to get a collection filtered by Category and another collection filtered by Tag and taking the intersection to get the result I want.
Thanks!
Michael
Hi ,
You can add logical operands to the LINQ condition.
Best wishes,
Ivan Dimitrov
the Telerik team
Thanks for the reply Ivan.
I'm not sure how I could apply logical operands here. Here's how I got this to "work". I know there's got to be a better way.
#region News
List<
NewsItem
> cItemsCatFilter = new List<
NewsItem
>();
List<
NewsItem
> cItemsTagFilter = new List<
NewsItem
>();
// Get Category Taxon
HierarchicalTaxon taxonCat = _resourceCats.SingleOrDefault(rc => rc.Title.ToLower() == "news");
// Get Items
string itemTypeName = "Telerik.Sitefinity.News.Model.NewsItem";
Type itemType = TypeResolutionService.ResolveType(itemTypeName);
IManager manager = ManagerBase.GetMappedManager(itemType, "");
ContentDataProviderBase contentProvider = manager.Provider as ContentDataProviderBase;
// Get collection filter by Category
IEnumerable n1 = GetItems(taxonCat, contentProvider, itemType);
cItemsCatFilter.AddRange(n1.OfType<
NewsItem
>());
// Get collection filter by Tag
IEnumerable n2 = GetItems(_tagTaxon, contentProvider, itemType);
cItemsTagFilter.AddRange(n2.OfType<
NewsItem
>());
// Filter by Tags and LifeCycle
var items = cItemsCatFilter.Intersect<
NewsItem
>(cItemsTagFilter, new Utility.NewsItemComparer())
.Where(ci => ci.Status != ContentLifecycleStatus.Live)
.OrderBy(ci => ci.PublicationDate)
.Take(5)
.ToList();
if (items.Count != 0)
StringBuilder sb = new StringBuilder();
for (int i = 0; i <
items.Count
; i++)
// Create link with Title
sb.AppendLine("<p>" + items[i].Title + "</
p
>");
sb.AppendLine("<
div
style
=
'height: 1px; background-color: #E2EBE9; margin: 5px 0;'
></
div
>");
//add More Link
sb.AppendLine("<
a
href
=
'#'
style
=
'color: Black;'
><
p
>More News »</
p
></
a
>");
ltlNews.Text = sb.ToString();
else
phNews.Visible = false;
#endregion
Hello,
You need to use the query as shown below
var categID = newGuid(
"generate a guid here"
);
var categID1 = newGuid(
"generate a guid here"
);
var content = App.WorkWith().ContentItem().Where(ci => ((IList<Guid>)ci.GetValue(
"Category"
)).Contains(categID) && ((IList<Guid>)ci.GetValue(
"Category"
)).Contains(categID1));
Hello,
This doesn't work for filtering by TAG (taxonomy [nme] = 'Tags'). The News object does not have a property TagsText.
Thanks!
Michael
Hi Michael,
The objects contain only a refence to the ID of the tag. You have to first get the Tag's ID using the taxonomy manager, then use Ivan's approach for filtering.
Kind regards,
Radoslav Georgiev
the Telerik team
Hello,
I stumbled upon the solution below after considering writing my own sprocs to get this data.
In using GetValue(this IDynamicFieldsContainer dataItem, string fieldName), I'm wondering where I can find all of the "fieldName" options.
Get News items by Tag:
var items = App.WorkWith().NewsItems()
.Where(ci => ((IList<
Guid
>)ci.GetValue("Tags")).Contains(tagTaxonID))
.Get();
var items = App.WorkWith().NewsItems()
.Where(ci => ((IList<
Guid
>)ci.GetValue("Category")).Contains(taxonCatID)).Get();
items = App.WorkWith().NewsItems()
.Where(ci => ((IList<
Guid
>)ci.GetValue("Tags")).Contains(tagTaxonID))
.Where(ci => ((IList<
Guid
>)ci.GetValue("Category")).Contains(taxonCatID))
.Get()
.Where(ci => ci.Status == ContentLifecycleStatus.Live)
.OrderByDescending(ci => ci.PublicationDate)
.ToList();
The Fluent API method doesn't work with ContentItems, just with NewsItem and probably other built in modules. It seems ContentItems is too generic for it. This is the error I get:
[ArgumentOutOfRangeException: Database mapped field does not exist. Parameter name: methodCallExpression Actual value was ci.FieldValue("Category").] Telerik.OpenAccess.Query.ExpressionCompiler.PerformDatabaseQueryImpl(Type type, Int32 elementAt, Object[] groupResolutionParamValues, Boolean single, Boolean checkOid) +736 Telerik.OpenAccess.Query.ExpressionCompiler.PerformDatabaseQuery(Type type, Int32 elementAt, Object[] groupResolutionParamValues, Boolean single, Boolean checkOid) +55 [InvalidOperationException: An exception occured during the execution of ' Extent<Telerik.Sitefinity.GenericContent.Model.ContentItem>.Where(item => (item.ApplicationName == value(Telerik.Sitefinity.Modules.GenericContent.Data.OpenAccessContentProvider+<>c__DisplayClass0).appName)).Where(ci => (ci.FieldValue("Category").Any(item => item.Equals(value(Telerik.Sitefinity.Data.Linq.OpenAccess.OpenAccessExpressionVisitor`2+<>c__DisplayClassa[Telerik.Sitefinity.GenericContent.Model.ContentItem,Telerik.Sitefinity.GenericContent.Model.ContentItem]).comparingObject)) AndAlso (Convert(Convert(Convert(ci.Status))) == 2)))'. See InnerException for more details. ] Telerik.OpenAccess.Query.ExpressionCompiler.PerformDatabaseQuery(Type type, Int32 elementAt, Object[] groupResolutionParamValues, Boolean single, Boolean checkOid) +244 Telerik.OpenAccess.Query.ExpressionExecution.PerformDatabaseQuery(Piece`1 piece, Object[] grpVals) +444 Telerik.OpenAccess.Query.Piece`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator() +37 Telerik.Sitefinity.Data.Linq.LinqQuery`2.GetEnumerator() +83 System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) +315 System.Linq.Enumerable.ToList(IEnumerable`1 source) +58 SitefinityWebApp.Custom.Categories.BuildCategory(String name) in C:\Data\IIS\...\Categories.ascx.cs:105 SitefinityWebApp.Custom.Categories.Page_Load(Object sender, EventArgs e) in C:\Data\IIS\...\Categories.ascx.cs:67 System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) +14 System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) +35 System.Web.UI.Control.OnLoad(EventArgs e) +91 System.Web.UI.Control.LoadRecursive() +74 System.Web.UI.Control.LoadRecursive() +146 System.Web.UI.Control.LoadRecursive() +146 System.Web.UI.Control.LoadRecursive() +146 System.Web.UI.Control.LoadRecursive() +146 System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +2207 |
Hi Basem,
Generic Content (now Shared Content) ContentItem type does not have Category field, nor Tags fields. Probably this is causing your problems.
Regards,
Radoslav Georgiev
the Telerik team
I was actually trying to do this for the custom Products Module. I was thinking ContentItem was the base class, but you refreshed my memory it is Content that is the base class. For a custom type like Products, it seems the Fluent API is not an option?
Hi Basem,
You can try working with the App.WorkWith().AnyContentItem<T> facade if you want to use fluent API for custom modules. There you can pass the type of your custom class and work with it.
Greetings,
Radoslav Georgiev
the Telerik team
Looks like this is only for retrieving a single item because there is no "where" clause. "AnyContentItems" (plural) would be sweet but doesn't exist
This is what I ended up doing for reference:
public
IEnumerable GetItems(ITaxon taxon)
string
itemTypeName =
typeof
(ProductItem).FullName;
Type itemType = TypeResolutionService.ResolveType(itemTypeName);
var manager = ManagerBase.GetMappedManager(itemType,
""
);
ContentDataProviderBase contentProvider = manager.Provider
as
ContentDataProviderBase;
TaxonomyPropertyDescriptor prop = TaxonomyManager.GetPropertyDescriptor(itemType, taxon);
int
? totalCount = 0;
var filter =
"Status = Master"
;
var items = contentProvider.GetItemsByTaxon(taxon.Id, prop.MetaField.IsSingleTaxon, prop.Name, itemType, filter, String.Empty, 0, 100,
ref
totalCount);
return
items;
Hi Basem,
I have logged this in PITS.
Regards,
Radoslav Georgiev
the Telerik team